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