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