1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sdext.hxx"
26 
27 #include "PresenterHelpView.hxx"
28 #include "PresenterButton.hxx"
29 #include "PresenterCanvasHelper.hxx"
30 #include "PresenterGeometryHelper.hxx"
31 #include "PresenterHelper.hxx"
32 #include "PresenterWindowManager.hxx"
33 #include <com/sun/star/awt/XWindowPeer.hpp>
34 #include <com/sun/star/container/XNameAccess.hpp>
35 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
36 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
37 #include <com/sun/star/rendering/CompositeOperation.hpp>
38 #include <com/sun/star/rendering/TextDirection.hpp>
39 #include <com/sun/star/util/Color.hpp>
40 #include <algorithm>
41 #include <vector>
42 #include <boost/bind.hpp>
43 
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::drawing::framework;
47 using ::rtl::OUString;
48 using ::std::vector;
49 
50 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
51 
52 
53 namespace sdext { namespace presenter {
54 
55 namespace {
56     const static sal_Int32 gnHorizontalGap (20);
57     const static sal_Int32 gnVerticalBorder (30);
58     const static sal_Int32 gnVerticalButtonPadding (12);
59 
60     class LineDescriptor
61     {
62     public:
63         LineDescriptor(void);
64         void AddPart (
65             const OUString& rsLine,
66             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
67         bool IsEmpty (void) const;
68 
69         OUString msLine;
70         geometry::RealSize2D maSize;
71         double mnVerticalOffset;
72 
73         void CalculateSize (const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
74     };
75 
76     class LineDescriptorList
77     {
78     public:
79         LineDescriptorList (
80             const OUString& rsText,
81             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
82             const sal_Int32 nMaximalWidth);
83 
84         void Update (
85             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
86             const sal_Int32 nMaximalWidth);
87 
88         double Paint(
89             const Reference<rendering::XCanvas>& rxCanvas,
90             const geometry::RealRectangle2D& rBBox,
91             const bool bFlushLeft,
92             const rendering::ViewState& rViewState,
93             rendering::RenderState& rRenderState,
94             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const;
95         double GetHeight (void) const;
96 
97     private:
98         const OUString msText;
99         ::boost::shared_ptr<vector<LineDescriptor> > mpLineDescriptors;
100 
101         void SplitText (const ::rtl::OUString& rsText, vector<rtl::OUString>& rTextParts);
102         void FormatText (
103             const vector<rtl::OUString>& rTextParts,
104             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
105             const sal_Int32 nMaximalWidth);
106     };
107 
108     class Block
109     {
110     public:
111         Block (const Block& rBlock);
112         Block (
113             const OUString& rsLeftText,
114             const OUString& rsRightText,
115             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
116             const sal_Int32 nMaximalWidth);
117         void Update (
118             const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
119             const sal_Int32 nMaximalWidth);
120 
121         LineDescriptorList maLeft;
122         LineDescriptorList maRight;
123     };
124 } // end of anonymous namespace
125 
126 class PresenterHelpView::TextContainer : public vector<boost::shared_ptr<Block> >
127 {
128 };
129 
130 
PresenterHelpView(const Reference<uno::XComponentContext> & rxContext,const Reference<XResourceId> & rxViewId,const Reference<frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)131 PresenterHelpView::PresenterHelpView (
132     const Reference<uno::XComponentContext>& rxContext,
133     const Reference<XResourceId>& rxViewId,
134     const Reference<frame::XController>& rxController,
135     const ::rtl::Reference<PresenterController>& rpPresenterController)
136     : PresenterHelpViewInterfaceBase(m_aMutex),
137       mxComponentContext(rxContext),
138       mxViewId(rxViewId),
139       mxPane(),
140       mxWindow(),
141       mxCanvas(),
142       mpPresenterController(rpPresenterController),
143       mpFont(),
144       mpTextContainer(),
145       mpCloseButton(),
146       mnSeparatorY(0),
147       mnMaximalWidth(0)
148 {
149     try
150     {
151         // Get the content window via the pane anchor.
152         Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
153         Reference<XConfigurationController> xCC (
154             xCM->getConfigurationController(), UNO_QUERY_THROW);
155         mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
156 
157         mxWindow = mxPane->getWindow();
158         ProvideCanvas();
159 
160         mxWindow->addWindowListener(this);
161         mxWindow->addPaintListener(this);
162         Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
163         if (xPeer.is())
164             xPeer->setBackground(util::Color(0xff000000));
165         mxWindow->setVisible(sal_True);
166 
167         if (mpPresenterController.is())
168         {
169             mpFont = mpPresenterController->GetViewFont(mxViewId->getResourceURL());
170             if (mpFont.get() != NULL)
171             {
172                 mpFont->PrepareFont(mxCanvas);
173             }
174         }
175 
176         // Create the close button.
177         mpCloseButton = PresenterButton::Create(
178             mxComponentContext,
179             mpPresenterController,
180             mpPresenterController->GetTheme(),
181             mxWindow,
182             mxCanvas,
183             A2S("HelpViewCloser"));
184 
185         ReadHelpStrings();
186         Resize();
187     }
188     catch (RuntimeException&)
189     {
190         mxViewId = NULL;
191         mxWindow = NULL;
192         throw;
193     }
194 }
195 
196 
197 
198 
~PresenterHelpView(void)199 PresenterHelpView::~PresenterHelpView (void)
200 {
201 }
202 
203 
204 
205 
disposing(void)206 void SAL_CALL PresenterHelpView::disposing (void)
207 {
208     mxViewId = NULL;
209 
210     if (mpCloseButton.is())
211     {
212         Reference<lang::XComponent> xComponent (
213             static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
214         mpCloseButton = NULL;
215         if (xComponent.is())
216             xComponent->dispose();
217     }
218 
219     if (mxWindow.is())
220     {
221         mxWindow->removeWindowListener(this);
222         mxWindow->removePaintListener(this);
223     }
224 }
225 
226 
227 
228 
229 //----- lang::XEventListener --------------------------------------------------
230 
disposing(const lang::EventObject & rEventObject)231 void SAL_CALL PresenterHelpView::disposing (const lang::EventObject& rEventObject)
232     throw (RuntimeException)
233 {
234     if (rEventObject.Source == mxCanvas)
235     {
236         mxCanvas = NULL;
237     }
238     else if (rEventObject.Source == mxWindow)
239     {
240         mxWindow = NULL;
241         dispose();
242     }
243 }
244 
245 
246 
247 
248 //----- XWindowListener -------------------------------------------------------
249 
windowResized(const awt::WindowEvent & rEvent)250 void SAL_CALL PresenterHelpView::windowResized (const awt::WindowEvent& rEvent)
251     throw (uno::RuntimeException)
252 {
253     (void)rEvent;
254     ThrowIfDisposed();
255     Resize();
256 }
257 
258 
259 
260 
windowMoved(const awt::WindowEvent & rEvent)261 void SAL_CALL PresenterHelpView::windowMoved (const awt::WindowEvent& rEvent)
262     throw (uno::RuntimeException)
263 {
264     (void)rEvent;
265     ThrowIfDisposed();
266 }
267 
268 
269 
270 
windowShown(const lang::EventObject & rEvent)271 void SAL_CALL PresenterHelpView::windowShown (const lang::EventObject& rEvent)
272     throw (uno::RuntimeException)
273 {
274     (void)rEvent;
275     ThrowIfDisposed();
276     Resize();
277 }
278 
279 
280 
281 
windowHidden(const lang::EventObject & rEvent)282 void SAL_CALL PresenterHelpView::windowHidden (const lang::EventObject& rEvent)
283     throw (uno::RuntimeException)
284 {
285     (void)rEvent;
286     ThrowIfDisposed();
287 }
288 
289 
290 
291 
292 //----- XPaintListener --------------------------------------------------------
293 
windowPaint(const css::awt::PaintEvent & rEvent)294 void SAL_CALL PresenterHelpView::windowPaint (const css::awt::PaintEvent& rEvent)
295     throw (RuntimeException)
296 {
297     Paint(rEvent.UpdateRect);
298 }
299 
300 
301 
302 
Paint(const awt::Rectangle & rUpdateBox)303 void PresenterHelpView::Paint (const awt::Rectangle& rUpdateBox)
304 {
305     ProvideCanvas();
306     if ( ! mxCanvas.is())
307         return;
308 
309     // Clear background.
310     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
311     mpPresenterController->GetCanvasHelper()->Paint(
312         mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
313         Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY),
314         rUpdateBox,
315         awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
316         awt::Rectangle());
317 
318     // Paint vertical divider.
319 
320     rendering::ViewState aViewState(
321         geometry::AffineMatrix2D(1,0,0, 0,1,0),
322         PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
323 
324     rendering::RenderState aRenderState (
325         geometry::AffineMatrix2D(1,0,0, 0,1,0),
326         NULL,
327         Sequence<double>(4),
328         rendering::CompositeOperation::SOURCE);
329     PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
330 
331     mxCanvas->drawLine(
332         geometry::RealPoint2D(aWindowBox.Width/2, gnVerticalBorder),
333         geometry::RealPoint2D(aWindowBox.Width/2, mnSeparatorY - gnVerticalBorder),
334         aViewState,
335         aRenderState);
336 
337     // Paint the horizontal separator.
338     mxCanvas->drawLine(
339         geometry::RealPoint2D(0, mnSeparatorY),
340         geometry::RealPoint2D(aWindowBox.Width, mnSeparatorY),
341         aViewState,
342         aRenderState);
343 
344     // Paint text.
345     double nY (gnVerticalBorder);
346     TextContainer::const_iterator iBlock (mpTextContainer->begin());
347     TextContainer::const_iterator iBlockEnd (mpTextContainer->end());
348     for ( ; iBlock!=iBlockEnd; ++iBlock)
349     {
350         const double nLeftHeight (
351             (*iBlock)->maLeft.Paint(mxCanvas,
352                 geometry::RealRectangle2D(
353                     gnHorizontalGap,
354                     nY,
355                     aWindowBox.Width/2 - gnHorizontalGap,
356                     aWindowBox.Height - gnVerticalBorder),
357                 false,
358                 aViewState,
359                 aRenderState,
360                 mpFont->mxFont));
361         const double nRightHeight (
362             (*iBlock)->maRight.Paint(mxCanvas,
363                 geometry::RealRectangle2D(
364                     aWindowBox.Width/2 + gnHorizontalGap,
365                     nY,
366                     aWindowBox.Width - gnHorizontalGap,
367                     aWindowBox.Height - gnVerticalBorder),
368                 true,
369                 aViewState,
370                 aRenderState,
371                 mpFont->mxFont));
372         nY += ::std::max(nLeftHeight,nRightHeight);
373     }
374 
375     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
376     if (xSpriteCanvas.is())
377         xSpriteCanvas->updateScreen(sal_False);
378 }
379 
380 
381 
382 
ReadHelpStrings(void)383 void PresenterHelpView::ReadHelpStrings (void)
384 {
385     mpTextContainer.reset(new TextContainer());
386     PresenterConfigurationAccess aConfiguration (
387         mxComponentContext,
388         OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"),
389         PresenterConfigurationAccess::READ_ONLY);
390     Reference<container::XNameAccess> xStrings (
391         aConfiguration.GetConfigurationNode(A2S("PresenterScreenSettings/HelpView/HelpStrings")),
392         UNO_QUERY);
393     PresenterConfigurationAccess::ForAll(
394         xStrings,
395         ::boost::bind(&PresenterHelpView::ProcessString, this, _2));
396 }
397 
398 
399 
400 
ProcessString(const Reference<beans::XPropertySet> & rsProperties)401 void PresenterHelpView::ProcessString (
402     const Reference<beans::XPropertySet>& rsProperties)
403 {
404     if ( ! rsProperties.is())
405         return;
406 
407     OUString sLeftText;
408     PresenterConfigurationAccess::GetProperty(rsProperties, A2S("Left")) >>= sLeftText;
409     OUString sRightText;
410     PresenterConfigurationAccess::GetProperty(rsProperties, A2S("Right")) >>= sRightText;
411 
412     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
413     mpTextContainer->push_back(
414         ::boost::shared_ptr<Block>(
415             new Block(sLeftText, sRightText, mpFont->mxFont, mnMaximalWidth)));
416 }
417 
418 
419 
420 
CheckFontSize(void)421 void PresenterHelpView::CheckFontSize (void)
422 {
423     if (mpFont.get() == NULL)
424         return;
425 
426     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
427     if (aWindowBox.Width<=0 || aWindowBox.Height<=0)
428         return;
429 
430     sal_Int32 nBestSize (6);
431 
432     // Scaling down and then reformatting can cause the text to be too large
433     // still.  So do this again and again until the text size is
434     // small enough.  Restrict the number of loops.
435     for (int nLoopCount=0; nLoopCount<5; ++nLoopCount)
436     {
437         double nY (gnVerticalBorder);
438         TextContainer::iterator iBlock (mpTextContainer->begin());
439         TextContainer::const_iterator iBlockEnd (mpTextContainer->end());
440         for ( ; iBlock!=iBlockEnd; ++iBlock)
441             nY += ::std::max(
442                 (*iBlock)->maLeft.GetHeight(),
443                 (*iBlock)->maRight.GetHeight());
444 
445         const double nHeightDifference (nY - (aWindowBox.Height-gnVerticalBorder));
446         if (nHeightDifference <= 0 && nHeightDifference > -50)
447         {
448             // We have found a good font size that is large and leaves not
449             // too much space below the help text.
450             return;
451         }
452 
453         // Font is too large.  Make it smaller.
454 
455         // Use a simple linear transformation to calculate initial guess of
456         // a size that lets all help text be shown inside the window.
457         const double nScale (double(aWindowBox.Height-gnVerticalBorder) / nY);
458         if (nScale > 0.95 && nScale <1.05)
459             break;
460 
461         sal_Int32 nFontSizeGuess (::std::max(sal_Int32(1),sal_Int32(mpFont->mnSize * nScale)));
462         if (nHeightDifference<0 && mpFont->mnSize>nBestSize)
463             nBestSize = mpFont->mnSize;
464         mpFont->mnSize = nFontSizeGuess;
465         mpFont->mxFont = NULL;
466         mpFont->PrepareFont(mxCanvas);
467 
468         // Reformat blocks.
469         for (iBlock=mpTextContainer->begin(); iBlock!=iBlockEnd; ++iBlock)
470             (*iBlock)->Update(mpFont->mxFont, mnMaximalWidth);
471     }
472 
473     if (nBestSize != mpFont->mnSize)
474     {
475         mpFont->mnSize = nBestSize;
476         mpFont->mxFont = NULL;
477         mpFont->PrepareFont(mxCanvas);
478 
479         // Reformat blocks.
480         for (TextContainer::iterator
481                  iBlock (mpTextContainer->begin()),
482                  iEnd (mpTextContainer->end());
483              iBlock!=iEnd;
484              ++iBlock)
485         {
486             (*iBlock)->Update(mpFont->mxFont, mnMaximalWidth);
487         }
488     }
489 }
490 
491 
492 
493 
494 //----- XResourceId -----------------------------------------------------------
495 
getResourceId(void)496 Reference<XResourceId> SAL_CALL PresenterHelpView::getResourceId (void)
497     throw (RuntimeException)
498 {
499     ThrowIfDisposed();
500     return mxViewId;
501 }
502 
503 
504 
505 
isAnchorOnly(void)506 sal_Bool SAL_CALL PresenterHelpView::isAnchorOnly (void)
507     throw (RuntimeException)
508 {
509     return false;
510 }
511 
512 
513 
514 
515 //-----------------------------------------------------------------------------
516 
ProvideCanvas(void)517 void PresenterHelpView::ProvideCanvas (void)
518 {
519     if ( ! mxCanvas.is() && mxPane.is())
520     {
521         mxCanvas = mxPane->getCanvas();
522         if ( ! mxCanvas.is())
523             return;
524         Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
525         if (xComponent.is())
526             xComponent->addEventListener(static_cast<awt::XPaintListener*>(this));
527 
528         if (mpCloseButton.is())
529             mpCloseButton->SetCanvas(mxCanvas, mxWindow);
530     }
531 }
532 
533 
534 
535 
Resize(void)536 void PresenterHelpView::Resize (void)
537 {
538     if (mpCloseButton.get() != NULL && mxWindow.is())
539     {
540         const awt::Rectangle aWindowBox (mxWindow->getPosSize());
541         mnMaximalWidth = (mxWindow->getPosSize().Width - 4*gnHorizontalGap) / 2;
542 
543         // Place vertical separator.
544         mnSeparatorY = aWindowBox.Height
545             - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
546 
547         mpCloseButton->SetCenter(geometry::RealPoint2D(
548             aWindowBox.Width/2,
549             aWindowBox.Height - mpCloseButton->GetSize().Height/2));
550 
551         CheckFontSize();
552     }
553 }
554 
555 
556 
557 
ThrowIfDisposed(void)558 void PresenterHelpView::ThrowIfDisposed (void)
559     throw (lang::DisposedException)
560 {
561 	if (rBHelper.bDisposed || rBHelper.bInDispose)
562 	{
563         throw lang::DisposedException (
564             OUString(RTL_CONSTASCII_USTRINGPARAM(
565                 "PresenterHelpView has been already disposed")),
566             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
567     }
568 }
569 
570 
571 
572 
573 //===== LineDescritor =========================================================
574 
575 namespace {
576 
LineDescriptor(void)577 LineDescriptor::LineDescriptor (void)
578     : msLine(),
579       maSize(0,0),
580       mnVerticalOffset(0)
581 {
582 }
583 
584 
585 
586 
AddPart(const OUString & rsLine,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont)587 void LineDescriptor::AddPart (
588     const OUString& rsLine,
589     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
590 {
591     msLine += rsLine;
592 
593     CalculateSize(rxFont);
594 }
595 
596 
597 
598 
IsEmpty(void) const599 bool LineDescriptor::IsEmpty (void) const
600 {
601     return msLine.getLength()==0;
602 }
603 
604 
605 
606 
CalculateSize(const css::uno::Reference<css::rendering::XCanvasFont> & rxFont)607 void LineDescriptor::CalculateSize (
608     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
609 {
610     OSL_ASSERT(rxFont.is());
611 
612     rendering::StringContext aContext (msLine, 0, msLine.getLength());
613     Reference<rendering::XTextLayout> xLayout (
614         rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
615     const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
616     maSize = css::geometry::RealSize2D(aTextBBox.X2 - aTextBBox.X1, aTextBBox.Y2 - aTextBBox.Y1);
617     mnVerticalOffset = aTextBBox.Y2;
618 }
619 
620 } // end of anonymous namespace
621 
622 
623 
624 
625 //===== LineDescriptorList ====================================================
626 
627 namespace {
628 
LineDescriptorList(const OUString & rsText,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)629 LineDescriptorList::LineDescriptorList (
630     const OUString& rsText,
631     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
632     const sal_Int32 nMaximalWidth)
633     : msText(rsText)
634 {
635     Update(rxFont, nMaximalWidth);
636 }
637 
638 
639 
640 
Paint(const Reference<rendering::XCanvas> & rxCanvas,const geometry::RealRectangle2D & rBBox,const bool bFlushLeft,const rendering::ViewState & rViewState,rendering::RenderState & rRenderState,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont) const641 double LineDescriptorList::Paint(
642     const Reference<rendering::XCanvas>& rxCanvas,
643     const geometry::RealRectangle2D& rBBox,
644     const bool bFlushLeft,
645     const rendering::ViewState& rViewState,
646     rendering::RenderState& rRenderState,
647     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const
648 {
649     if ( ! rxCanvas.is())
650         return 0;
651 
652     double nY (rBBox.Y1);
653     vector<LineDescriptor>::const_iterator iLine (mpLineDescriptors->begin());
654     vector<LineDescriptor>::const_iterator iEnd (mpLineDescriptors->end());
655     for ( ; iLine!=iEnd; ++iLine)
656     {
657         double nX (rBBox.X1);
658         if ( ! bFlushLeft)
659             nX = rBBox.X2 - iLine->maSize.Width;
660         rRenderState.AffineTransform.m02 = nX;
661         rRenderState.AffineTransform.m12 = nY + iLine->maSize.Height - iLine->mnVerticalOffset;
662 
663         const rendering::StringContext aContext (iLine->msLine, 0, iLine->msLine.getLength());
664 
665         rxCanvas->drawText (
666             aContext,
667             rxFont,
668             rViewState,
669             rRenderState,
670             rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
671 
672         nY += iLine->maSize.Height * 1.2;
673     }
674 
675     return nY - rBBox.Y1;
676 }
677 
678 
679 
680 
GetHeight(void) const681 double LineDescriptorList::GetHeight (void) const
682 {
683     double nHeight (0);
684     vector<LineDescriptor>::const_iterator iLine (mpLineDescriptors->begin());
685     vector<LineDescriptor>::const_iterator iEnd (mpLineDescriptors->end());
686     for ( ; iLine!=iEnd; ++iLine)
687         nHeight += iLine->maSize.Height * 1.2;
688 
689     return nHeight;
690 }
691 
692 
693 
694 
Update(const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)695 void LineDescriptorList::Update (
696     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
697     const sal_Int32 nMaximalWidth)
698 {
699     vector<OUString> aTextParts;
700     SplitText(msText, aTextParts);
701     FormatText(aTextParts, rxFont, nMaximalWidth);
702 }
703 
704 
705 
706 
SplitText(const OUString & rsText,vector<OUString> & rTextParts)707 void LineDescriptorList::SplitText (
708     const OUString& rsText,
709     vector<OUString>& rTextParts)
710 {
711     const sal_Char cQuote ('\'');
712     const sal_Char cSeparator (',');
713 
714     sal_Int32 nIndex (0);
715     sal_Int32 nStart (0);
716     sal_Int32 nLength (rsText.getLength());
717     bool bIsQuoted (false);
718     while (nIndex < nLength)
719     {
720         const sal_Int32 nQuoteIndex (rsText.indexOf(cQuote, nIndex));
721         const sal_Int32 nSeparatorIndex (rsText.indexOf(cSeparator, nIndex));
722         if (nQuoteIndex>=0 && (nSeparatorIndex==-1 || nQuoteIndex<nSeparatorIndex))
723         {
724             bIsQuoted = !bIsQuoted;
725             nIndex = nQuoteIndex+1;
726             continue;
727         }
728 
729         const sal_Int32 nNextIndex = nSeparatorIndex;
730         if (nNextIndex < 0)
731         {
732             break;
733         }
734         else if ( ! bIsQuoted)
735         {
736             rTextParts.push_back(rsText.copy(nStart, nNextIndex-nStart));
737             nStart = nNextIndex + 1;
738         }
739         nIndex = nNextIndex+1;
740     }
741     if (nStart < nLength)
742         rTextParts.push_back(rsText.copy(nStart, nLength-nStart));
743 }
744 
745 
746 
747 
FormatText(const vector<OUString> & rTextParts,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)748 void LineDescriptorList::FormatText (
749     const vector<OUString>& rTextParts,
750     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
751     const sal_Int32 nMaximalWidth)
752 {
753     LineDescriptor aLineDescriptor;
754 
755     mpLineDescriptors.reset(new vector<LineDescriptor>());
756 
757     vector<OUString>::const_iterator iPart (rTextParts.begin());
758     vector<OUString>::const_iterator iEnd (rTextParts.end());
759     for ( ; iPart!=iEnd; ++iPart)
760     {
761         if (aLineDescriptor.IsEmpty())
762         {
763             // Avoid empty lines.
764             aLineDescriptor.AddPart(*iPart, rxFont);
765         }
766         else if (PresenterCanvasHelper::GetTextSize(
767             rxFont, aLineDescriptor.msLine+A2S(", ")+*iPart).Width > nMaximalWidth)
768         {
769             aLineDescriptor.AddPart(A2S(","), rxFont);
770             mpLineDescriptors->push_back(aLineDescriptor);
771             aLineDescriptor = LineDescriptor();
772             aLineDescriptor.AddPart(*iPart, rxFont);
773         }
774         else
775         {
776             aLineDescriptor.AddPart(A2S(", ")+*iPart, rxFont);
777         }
778     }
779     if ( ! aLineDescriptor.IsEmpty())
780     {
781         mpLineDescriptors->push_back(aLineDescriptor);
782     }
783 }
784 
785 
786 } // end of anonymous namespace
787 
788 
789 
790 
791 //===== Block =================================================================
792 
793 namespace {
794 
Block(const OUString & rsLeftText,const OUString & rsRightText,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)795 Block::Block (
796     const OUString& rsLeftText,
797     const OUString& rsRightText,
798     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
799     const sal_Int32 nMaximalWidth)
800     : maLeft(rsLeftText, rxFont, nMaximalWidth),
801       maRight(rsRightText, rxFont, nMaximalWidth)
802 {
803 }
804 
805 
806 
Update(const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)807 void Block::Update (
808     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
809     const sal_Int32 nMaximalWidth)
810 {
811     maLeft.Update(rxFont, nMaximalWidth);
812     maRight.Update(rxFont, nMaximalWidth);
813 }
814 
815 } // end of anonymous namespace
816 
817 } } // end of namespace ::sdext::presenter
818 
819 
820