xref: /trunk/main/sdext/source/presenter/PresenterHelpView.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
233     if (rEventObject.Source == mxCanvas)
234     {
235         mxCanvas = NULL;
236     }
237     else if (rEventObject.Source == mxWindow)
238     {
239         mxWindow = NULL;
240         dispose();
241     }
242 }
243 
244 
245 
246 
247 //----- XWindowListener -------------------------------------------------------
248 
windowResized(const awt::WindowEvent & rEvent)249 void SAL_CALL PresenterHelpView::windowResized (const awt::WindowEvent& rEvent)
250 {
251     (void)rEvent;
252     ThrowIfDisposed();
253     Resize();
254 }
255 
256 
257 
258 
windowMoved(const awt::WindowEvent & rEvent)259 void SAL_CALL PresenterHelpView::windowMoved (const awt::WindowEvent& rEvent)
260 {
261     (void)rEvent;
262     ThrowIfDisposed();
263 }
264 
265 
266 
267 
windowShown(const lang::EventObject & rEvent)268 void SAL_CALL PresenterHelpView::windowShown (const lang::EventObject& rEvent)
269 {
270     (void)rEvent;
271     ThrowIfDisposed();
272     Resize();
273 }
274 
275 
276 
277 
windowHidden(const lang::EventObject & rEvent)278 void SAL_CALL PresenterHelpView::windowHidden (const lang::EventObject& rEvent)
279 {
280     (void)rEvent;
281     ThrowIfDisposed();
282 }
283 
284 
285 
286 
287 //----- XPaintListener --------------------------------------------------------
288 
windowPaint(const css::awt::PaintEvent & rEvent)289 void SAL_CALL PresenterHelpView::windowPaint (const css::awt::PaintEvent& rEvent)
290 {
291     Paint(rEvent.UpdateRect);
292 }
293 
294 
295 
296 
Paint(const awt::Rectangle & rUpdateBox)297 void PresenterHelpView::Paint (const awt::Rectangle& rUpdateBox)
298 {
299     ProvideCanvas();
300     if ( ! mxCanvas.is())
301         return;
302 
303     // Clear background.
304     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
305     mpPresenterController->GetCanvasHelper()->Paint(
306         mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
307         Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY),
308         rUpdateBox,
309         awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
310         awt::Rectangle());
311 
312     // Paint vertical divider.
313 
314     rendering::ViewState aViewState(
315         geometry::AffineMatrix2D(1,0,0, 0,1,0),
316         PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
317 
318     rendering::RenderState aRenderState (
319         geometry::AffineMatrix2D(1,0,0, 0,1,0),
320         NULL,
321         Sequence<double>(4),
322         rendering::CompositeOperation::SOURCE);
323     PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
324 
325     mxCanvas->drawLine(
326         geometry::RealPoint2D(aWindowBox.Width/2, gnVerticalBorder),
327         geometry::RealPoint2D(aWindowBox.Width/2, mnSeparatorY - gnVerticalBorder),
328         aViewState,
329         aRenderState);
330 
331     // Paint the horizontal separator.
332     mxCanvas->drawLine(
333         geometry::RealPoint2D(0, mnSeparatorY),
334         geometry::RealPoint2D(aWindowBox.Width, mnSeparatorY),
335         aViewState,
336         aRenderState);
337 
338     // Paint text.
339     double nY (gnVerticalBorder);
340     TextContainer::const_iterator iBlock (mpTextContainer->begin());
341     TextContainer::const_iterator iBlockEnd (mpTextContainer->end());
342     for ( ; iBlock!=iBlockEnd; ++iBlock)
343     {
344         const double nLeftHeight (
345             (*iBlock)->maLeft.Paint(mxCanvas,
346                 geometry::RealRectangle2D(
347                     gnHorizontalGap,
348                     nY,
349                     aWindowBox.Width/2 - gnHorizontalGap,
350                     aWindowBox.Height - gnVerticalBorder),
351                 false,
352                 aViewState,
353                 aRenderState,
354                 mpFont->mxFont));
355         const double nRightHeight (
356             (*iBlock)->maRight.Paint(mxCanvas,
357                 geometry::RealRectangle2D(
358                     aWindowBox.Width/2 + gnHorizontalGap,
359                     nY,
360                     aWindowBox.Width - gnHorizontalGap,
361                     aWindowBox.Height - gnVerticalBorder),
362                 true,
363                 aViewState,
364                 aRenderState,
365                 mpFont->mxFont));
366         nY += ::std::max(nLeftHeight,nRightHeight);
367     }
368 
369     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
370     if (xSpriteCanvas.is())
371         xSpriteCanvas->updateScreen(sal_False);
372 }
373 
374 
375 
376 
ReadHelpStrings(void)377 void PresenterHelpView::ReadHelpStrings (void)
378 {
379     mpTextContainer.reset(new TextContainer());
380     PresenterConfigurationAccess aConfiguration (
381         mxComponentContext,
382         OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"),
383         PresenterConfigurationAccess::READ_ONLY);
384     Reference<container::XNameAccess> xStrings (
385         aConfiguration.GetConfigurationNode(A2S("PresenterScreenSettings/HelpView/HelpStrings")),
386         UNO_QUERY);
387     PresenterConfigurationAccess::ForAll(
388         xStrings,
389         ::boost::bind(&PresenterHelpView::ProcessString, this, _2));
390 }
391 
392 
393 
394 
ProcessString(const Reference<beans::XPropertySet> & rsProperties)395 void PresenterHelpView::ProcessString (
396     const Reference<beans::XPropertySet>& rsProperties)
397 {
398     if ( ! rsProperties.is())
399         return;
400 
401     OUString sLeftText;
402     PresenterConfigurationAccess::GetProperty(rsProperties, A2S("Left")) >>= sLeftText;
403     OUString sRightText;
404     PresenterConfigurationAccess::GetProperty(rsProperties, A2S("Right")) >>= sRightText;
405 
406     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
407     mpTextContainer->push_back(
408         ::boost::shared_ptr<Block>(
409             new Block(sLeftText, sRightText, mpFont->mxFont, mnMaximalWidth)));
410 }
411 
412 
413 
414 
CheckFontSize(void)415 void PresenterHelpView::CheckFontSize (void)
416 {
417     if (mpFont.get() == NULL)
418         return;
419 
420     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
421     if (aWindowBox.Width<=0 || aWindowBox.Height<=0)
422         return;
423 
424     sal_Int32 nBestSize (6);
425 
426     // Scaling down and then reformatting can cause the text to be too large
427     // still.  So do this again and again until the text size is
428     // small enough.  Restrict the number of loops.
429     for (int nLoopCount=0; nLoopCount<5; ++nLoopCount)
430     {
431         double nY (gnVerticalBorder);
432         TextContainer::iterator iBlock (mpTextContainer->begin());
433         TextContainer::const_iterator iBlockEnd (mpTextContainer->end());
434         for ( ; iBlock!=iBlockEnd; ++iBlock)
435             nY += ::std::max(
436                 (*iBlock)->maLeft.GetHeight(),
437                 (*iBlock)->maRight.GetHeight());
438 
439         const double nHeightDifference (nY - (aWindowBox.Height-gnVerticalBorder));
440         if (nHeightDifference <= 0 && nHeightDifference > -50)
441         {
442             // We have found a good font size that is large and leaves not
443             // too much space below the help text.
444             return;
445         }
446 
447         // Font is too large.  Make it smaller.
448 
449         // Use a simple linear transformation to calculate initial guess of
450         // a size that lets all help text be shown inside the window.
451         const double nScale (double(aWindowBox.Height-gnVerticalBorder) / nY);
452         if (nScale > 0.95 && nScale <1.05)
453             break;
454 
455         sal_Int32 nFontSizeGuess (::std::max(sal_Int32(1),sal_Int32(mpFont->mnSize * nScale)));
456         if (nHeightDifference<0 && mpFont->mnSize>nBestSize)
457             nBestSize = mpFont->mnSize;
458         mpFont->mnSize = nFontSizeGuess;
459         mpFont->mxFont = NULL;
460         mpFont->PrepareFont(mxCanvas);
461 
462         // Reformat blocks.
463         for (iBlock=mpTextContainer->begin(); iBlock!=iBlockEnd; ++iBlock)
464             (*iBlock)->Update(mpFont->mxFont, mnMaximalWidth);
465     }
466 
467     if (nBestSize != mpFont->mnSize)
468     {
469         mpFont->mnSize = nBestSize;
470         mpFont->mxFont = NULL;
471         mpFont->PrepareFont(mxCanvas);
472 
473         // Reformat blocks.
474         for (TextContainer::iterator
475                  iBlock (mpTextContainer->begin()),
476                  iEnd (mpTextContainer->end());
477              iBlock!=iEnd;
478              ++iBlock)
479         {
480             (*iBlock)->Update(mpFont->mxFont, mnMaximalWidth);
481         }
482     }
483 }
484 
485 
486 
487 
488 //----- XResourceId -----------------------------------------------------------
489 
getResourceId(void)490 Reference<XResourceId> SAL_CALL PresenterHelpView::getResourceId (void)
491 {
492     ThrowIfDisposed();
493     return mxViewId;
494 }
495 
496 
497 
498 
isAnchorOnly(void)499 sal_Bool SAL_CALL PresenterHelpView::isAnchorOnly (void)
500 {
501     return false;
502 }
503 
504 
505 
506 
507 //-----------------------------------------------------------------------------
508 
ProvideCanvas(void)509 void PresenterHelpView::ProvideCanvas (void)
510 {
511     if ( ! mxCanvas.is() && mxPane.is())
512     {
513         mxCanvas = mxPane->getCanvas();
514         if ( ! mxCanvas.is())
515             return;
516         Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
517         if (xComponent.is())
518             xComponent->addEventListener(static_cast<awt::XPaintListener*>(this));
519 
520         if (mpCloseButton.is())
521             mpCloseButton->SetCanvas(mxCanvas, mxWindow);
522     }
523 }
524 
525 
526 
527 
Resize(void)528 void PresenterHelpView::Resize (void)
529 {
530     if (mpCloseButton.get() != NULL && mxWindow.is())
531     {
532         const awt::Rectangle aWindowBox (mxWindow->getPosSize());
533         mnMaximalWidth = (mxWindow->getPosSize().Width - 4*gnHorizontalGap) / 2;
534 
535         // Place vertical separator.
536         mnSeparatorY = aWindowBox.Height
537             - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
538 
539         mpCloseButton->SetCenter(geometry::RealPoint2D(
540             aWindowBox.Width/2,
541             aWindowBox.Height - mpCloseButton->GetSize().Height/2));
542 
543         CheckFontSize();
544     }
545 }
546 
547 
548 
549 
ThrowIfDisposed(void)550 void PresenterHelpView::ThrowIfDisposed (void)
551 {
552     if (rBHelper.bDisposed || rBHelper.bInDispose)
553     {
554         throw lang::DisposedException (
555             OUString(RTL_CONSTASCII_USTRINGPARAM(
556                 "PresenterHelpView has been already disposed")),
557             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
558     }
559 }
560 
561 
562 
563 
564 //===== LineDescritor =========================================================
565 
566 namespace {
567 
LineDescriptor(void)568 LineDescriptor::LineDescriptor (void)
569     : msLine(),
570       maSize(0,0),
571       mnVerticalOffset(0)
572 {
573 }
574 
575 
576 
577 
AddPart(const OUString & rsLine,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont)578 void LineDescriptor::AddPart (
579     const OUString& rsLine,
580     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
581 {
582     msLine += rsLine;
583 
584     CalculateSize(rxFont);
585 }
586 
587 
588 
589 
IsEmpty(void) const590 bool LineDescriptor::IsEmpty (void) const
591 {
592     return msLine.getLength()==0;
593 }
594 
595 
596 
597 
CalculateSize(const css::uno::Reference<css::rendering::XCanvasFont> & rxFont)598 void LineDescriptor::CalculateSize (
599     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
600 {
601     OSL_ASSERT(rxFont.is());
602 
603     rendering::StringContext aContext (msLine, 0, msLine.getLength());
604     Reference<rendering::XTextLayout> xLayout (
605         rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
606     const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
607     maSize = css::geometry::RealSize2D(aTextBBox.X2 - aTextBBox.X1, aTextBBox.Y2 - aTextBBox.Y1);
608     mnVerticalOffset = aTextBBox.Y2;
609 }
610 
611 } // end of anonymous namespace
612 
613 
614 
615 
616 //===== LineDescriptorList ====================================================
617 
618 namespace {
619 
LineDescriptorList(const OUString & rsText,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)620 LineDescriptorList::LineDescriptorList (
621     const OUString& rsText,
622     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
623     const sal_Int32 nMaximalWidth)
624     : msText(rsText)
625 {
626     Update(rxFont, nMaximalWidth);
627 }
628 
629 
630 
631 
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) const632 double LineDescriptorList::Paint(
633     const Reference<rendering::XCanvas>& rxCanvas,
634     const geometry::RealRectangle2D& rBBox,
635     const bool bFlushLeft,
636     const rendering::ViewState& rViewState,
637     rendering::RenderState& rRenderState,
638     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont) const
639 {
640     if ( ! rxCanvas.is())
641         return 0;
642 
643     double nY (rBBox.Y1);
644     vector<LineDescriptor>::const_iterator iLine (mpLineDescriptors->begin());
645     vector<LineDescriptor>::const_iterator iEnd (mpLineDescriptors->end());
646     for ( ; iLine!=iEnd; ++iLine)
647     {
648         double nX (rBBox.X1);
649         if ( ! bFlushLeft)
650             nX = rBBox.X2 - iLine->maSize.Width;
651         rRenderState.AffineTransform.m02 = nX;
652         rRenderState.AffineTransform.m12 = nY + iLine->maSize.Height - iLine->mnVerticalOffset;
653 
654         const rendering::StringContext aContext (iLine->msLine, 0, iLine->msLine.getLength());
655 
656         rxCanvas->drawText (
657             aContext,
658             rxFont,
659             rViewState,
660             rRenderState,
661             rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
662 
663         nY += iLine->maSize.Height * 1.2;
664     }
665 
666     return nY - rBBox.Y1;
667 }
668 
669 
670 
671 
GetHeight(void) const672 double LineDescriptorList::GetHeight (void) const
673 {
674     double nHeight (0);
675     vector<LineDescriptor>::const_iterator iLine (mpLineDescriptors->begin());
676     vector<LineDescriptor>::const_iterator iEnd (mpLineDescriptors->end());
677     for ( ; iLine!=iEnd; ++iLine)
678         nHeight += iLine->maSize.Height * 1.2;
679 
680     return nHeight;
681 }
682 
683 
684 
685 
Update(const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)686 void LineDescriptorList::Update (
687     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
688     const sal_Int32 nMaximalWidth)
689 {
690     vector<OUString> aTextParts;
691     SplitText(msText, aTextParts);
692     FormatText(aTextParts, rxFont, nMaximalWidth);
693 }
694 
695 
696 
697 
SplitText(const OUString & rsText,vector<OUString> & rTextParts)698 void LineDescriptorList::SplitText (
699     const OUString& rsText,
700     vector<OUString>& rTextParts)
701 {
702     const sal_Char cQuote ('\'');
703     const sal_Char cSeparator (',');
704 
705     sal_Int32 nIndex (0);
706     sal_Int32 nStart (0);
707     sal_Int32 nLength (rsText.getLength());
708     bool bIsQuoted (false);
709     while (nIndex < nLength)
710     {
711         const sal_Int32 nQuoteIndex (rsText.indexOf(cQuote, nIndex));
712         const sal_Int32 nSeparatorIndex (rsText.indexOf(cSeparator, nIndex));
713         if (nQuoteIndex>=0 && (nSeparatorIndex==-1 || nQuoteIndex<nSeparatorIndex))
714         {
715             bIsQuoted = !bIsQuoted;
716             nIndex = nQuoteIndex+1;
717             continue;
718         }
719 
720         const sal_Int32 nNextIndex = nSeparatorIndex;
721         if (nNextIndex < 0)
722         {
723             break;
724         }
725         else if ( ! bIsQuoted)
726         {
727             rTextParts.push_back(rsText.copy(nStart, nNextIndex-nStart));
728             nStart = nNextIndex + 1;
729         }
730         nIndex = nNextIndex+1;
731     }
732     if (nStart < nLength)
733         rTextParts.push_back(rsText.copy(nStart, nLength-nStart));
734 }
735 
736 
737 
738 
FormatText(const vector<OUString> & rTextParts,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)739 void LineDescriptorList::FormatText (
740     const vector<OUString>& rTextParts,
741     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
742     const sal_Int32 nMaximalWidth)
743 {
744     LineDescriptor aLineDescriptor;
745 
746     mpLineDescriptors.reset(new vector<LineDescriptor>());
747 
748     vector<OUString>::const_iterator iPart (rTextParts.begin());
749     vector<OUString>::const_iterator iEnd (rTextParts.end());
750     for ( ; iPart!=iEnd; ++iPart)
751     {
752         if (aLineDescriptor.IsEmpty())
753         {
754             // Avoid empty lines.
755             aLineDescriptor.AddPart(*iPart, rxFont);
756         }
757         else if (PresenterCanvasHelper::GetTextSize(
758             rxFont, aLineDescriptor.msLine+A2S(", ")+*iPart).Width > nMaximalWidth)
759         {
760             aLineDescriptor.AddPart(A2S(","), rxFont);
761             mpLineDescriptors->push_back(aLineDescriptor);
762             aLineDescriptor = LineDescriptor();
763             aLineDescriptor.AddPart(*iPart, rxFont);
764         }
765         else
766         {
767             aLineDescriptor.AddPart(A2S(", ")+*iPart, rxFont);
768         }
769     }
770     if ( ! aLineDescriptor.IsEmpty())
771     {
772         mpLineDescriptors->push_back(aLineDescriptor);
773     }
774 }
775 
776 
777 } // end of anonymous namespace
778 
779 
780 
781 
782 //===== Block =================================================================
783 
784 namespace {
785 
Block(const OUString & rsLeftText,const OUString & rsRightText,const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)786 Block::Block (
787     const OUString& rsLeftText,
788     const OUString& rsRightText,
789     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
790     const sal_Int32 nMaximalWidth)
791     : maLeft(rsLeftText, rxFont, nMaximalWidth),
792       maRight(rsRightText, rxFont, nMaximalWidth)
793 {
794 }
795 
796 
797 
Update(const css::uno::Reference<css::rendering::XCanvasFont> & rxFont,const sal_Int32 nMaximalWidth)798 void Block::Update (
799     const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
800     const sal_Int32 nMaximalWidth)
801 {
802     maLeft.Update(rxFont, nMaximalWidth);
803     maRight.Update(rxFont, nMaximalWidth);
804 }
805 
806 } // end of anonymous namespace
807 
808 } } // end of namespace ::sdext::presenter
809