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