summaryrefslogtreecommitdiffstats
path: root/sdext/source/presenter/PresenterHelpView.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sdext/source/presenter/PresenterHelpView.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sdext/source/presenter/PresenterHelpView.cxx')
-rw-r--r--sdext/source/presenter/PresenterHelpView.cxx747
1 files changed, 747 insertions, 0 deletions
diff --git a/sdext/source/presenter/PresenterHelpView.cxx b/sdext/source/presenter/PresenterHelpView.cxx
new file mode 100644
index 000000000..74adeedd1
--- /dev/null
+++ b/sdext/source/presenter/PresenterHelpView.cxx
@@ -0,0 +1,747 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/settings.hxx>
+#include "PresenterHelpView.hxx"
+#include "PresenterButton.hxx"
+#include "PresenterCanvasHelper.hxx"
+#include "PresenterGeometryHelper.hxx"
+#include <com/sun/star/awt/XWindowPeer.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/drawing/framework/XConfigurationController.hpp>
+#include <com/sun/star/drawing/framework/XControllerManager.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/TextDirection.hpp>
+#include <com/sun/star/util/Color.hpp>
+#include <algorithm>
+#include <numeric>
+#include <string_view>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing::framework;
+using ::std::vector;
+
+namespace sdext::presenter {
+
+namespace {
+ const sal_Int32 gnHorizontalGap (20);
+ const sal_Int32 gnVerticalBorder (30);
+ const sal_Int32 gnVerticalButtonPadding (12);
+
+ class LineDescriptor
+ {
+ public:
+ LineDescriptor();
+ void AddPart (
+ std::u16string_view rsLine,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
+ bool IsEmpty() const;
+
+ OUString msLine;
+ geometry::RealSize2D maSize;
+ double mnVerticalOffset;
+
+ void CalculateSize (const css::uno::Reference<css::rendering::XCanvasFont>& rxFont);
+ };
+
+ class LineDescriptorList
+ {
+ public:
+ LineDescriptorList (
+ const OUString& rsText,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth);
+
+ void Update (
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth);
+
+ double 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) const;
+ double GetHeight() const;
+
+ private:
+ const OUString msText;
+ std::shared_ptr<vector<LineDescriptor> > mpLineDescriptors;
+
+ static void SplitText (const OUString& rsText, vector<OUString>& rTextParts);
+ void FormatText (
+ const vector<OUString>& rTextParts,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth);
+ };
+
+ class Block
+ {
+ public:
+ Block (
+ const OUString& rsLeftText,
+ const OUString& rsRightText,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth);
+ Block(const Block&) = delete;
+ Block& operator=(const Block&) = delete;
+ void Update (
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth);
+
+ LineDescriptorList maLeft;
+ LineDescriptorList maRight;
+ };
+} // end of anonymous namespace
+
+class PresenterHelpView::TextContainer : public vector<std::shared_ptr<Block> >
+{
+};
+
+PresenterHelpView::PresenterHelpView (
+ const Reference<uno::XComponentContext>& rxContext,
+ const Reference<XResourceId>& rxViewId,
+ const Reference<frame::XController>& rxController,
+ const ::rtl::Reference<PresenterController>& rpPresenterController)
+ : PresenterHelpViewInterfaceBase(m_aMutex),
+ mxComponentContext(rxContext),
+ mxViewId(rxViewId),
+ mpPresenterController(rpPresenterController),
+ mnSeparatorY(0),
+ mnMaximalWidth(0)
+{
+ try
+ {
+ // Get the content window via the pane anchor.
+ Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
+ Reference<XConfigurationController> xCC (
+ xCM->getConfigurationController(), UNO_SET_THROW);
+ mxPane.set(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
+
+ mxWindow = mxPane->getWindow();
+ ProvideCanvas();
+
+ mxWindow->addWindowListener(this);
+ mxWindow->addPaintListener(this);
+ Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
+ if (xPeer.is())
+ xPeer->setBackground(util::Color(0xff000000));
+ mxWindow->setVisible(true);
+
+ if (mpPresenterController.is())
+ {
+ mpFont = mpPresenterController->GetViewFont(mxViewId->getResourceURL());
+ if (mpFont)
+ {
+ mpFont->PrepareFont(mxCanvas);
+ }
+ }
+
+ // Create the close button.
+ mpCloseButton = PresenterButton::Create(
+ mxComponentContext,
+ mpPresenterController,
+ mpPresenterController->GetTheme(),
+ mxWindow,
+ mxCanvas,
+ "HelpViewCloser");
+
+ ReadHelpStrings();
+ Resize();
+ }
+ catch (RuntimeException&)
+ {
+ mxViewId = nullptr;
+ mxWindow = nullptr;
+ throw;
+ }
+}
+
+PresenterHelpView::~PresenterHelpView()
+{
+}
+
+void SAL_CALL PresenterHelpView::disposing()
+{
+ mxViewId = nullptr;
+
+ if (mpCloseButton.is())
+ {
+ Reference<lang::XComponent> xComponent = mpCloseButton;
+ mpCloseButton = nullptr;
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+
+ if (mxWindow.is())
+ {
+ mxWindow->removeWindowListener(this);
+ mxWindow->removePaintListener(this);
+ }
+}
+
+//----- lang::XEventListener --------------------------------------------------
+
+void SAL_CALL PresenterHelpView::disposing (const lang::EventObject& rEventObject)
+{
+ if (rEventObject.Source == mxCanvas)
+ {
+ mxCanvas = nullptr;
+ }
+ else if (rEventObject.Source == mxWindow)
+ {
+ mxWindow = nullptr;
+ dispose();
+ }
+}
+
+//----- XWindowListener -------------------------------------------------------
+
+void SAL_CALL PresenterHelpView::windowResized (const awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+ Resize();
+}
+
+void SAL_CALL PresenterHelpView::windowMoved (const awt::WindowEvent&)
+{
+ ThrowIfDisposed();
+}
+
+void SAL_CALL PresenterHelpView::windowShown (const lang::EventObject&)
+{
+ ThrowIfDisposed();
+ Resize();
+}
+
+void SAL_CALL PresenterHelpView::windowHidden (const lang::EventObject&)
+{
+ ThrowIfDisposed();
+}
+
+//----- XPaintListener --------------------------------------------------------
+
+void SAL_CALL PresenterHelpView::windowPaint (const css::awt::PaintEvent& rEvent)
+{
+ Paint(rEvent.UpdateRect);
+}
+
+void PresenterHelpView::Paint (const awt::Rectangle& rUpdateBox)
+{
+ ProvideCanvas();
+ if ( ! mxCanvas.is())
+ return;
+
+ // Clear background.
+ const awt::Rectangle aWindowBox (mxWindow->getPosSize());
+ mpPresenterController->GetCanvasHelper()->Paint(
+ mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
+ mxCanvas,
+ rUpdateBox,
+ awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
+ awt::Rectangle());
+
+ // Paint vertical divider.
+
+ rendering::ViewState aViewState(
+ geometry::AffineMatrix2D(1,0,0, 0,1,0),
+ PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
+
+ rendering::RenderState aRenderState (
+ geometry::AffineMatrix2D(1,0,0, 0,1,0),
+ nullptr,
+ Sequence<double>(4),
+ rendering::CompositeOperation::SOURCE);
+ PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
+
+ mxCanvas->drawLine(
+ geometry::RealPoint2D((aWindowBox.Width/2.0), gnVerticalBorder),
+ geometry::RealPoint2D((aWindowBox.Width/2.0), mnSeparatorY - gnVerticalBorder),
+ aViewState,
+ aRenderState);
+
+ // Paint the horizontal separator.
+ mxCanvas->drawLine(
+ geometry::RealPoint2D(0, mnSeparatorY),
+ geometry::RealPoint2D(aWindowBox.Width, mnSeparatorY),
+ aViewState,
+ aRenderState);
+
+ // Paint text.
+ double nY (gnVerticalBorder);
+ for (const auto& rxBlock : *mpTextContainer)
+ {
+ sal_Int32 LeftX1 = gnHorizontalGap;
+ sal_Int32 LeftX2 = aWindowBox.Width/2 - gnHorizontalGap;
+ sal_Int32 RightX1 = aWindowBox.Width/2 + gnHorizontalGap;
+ sal_Int32 RightX2 = aWindowBox.Width - gnHorizontalGap;
+ /* check whether RTL interface or not
+ then replace the windowbox position */
+ if(AllSettings::GetLayoutRTL())
+ {
+ LeftX1 = aWindowBox.Width/2 + gnHorizontalGap;
+ LeftX2 = aWindowBox.Width - gnHorizontalGap;
+ RightX1 = gnHorizontalGap;
+ RightX2 = aWindowBox.Width/2 - gnHorizontalGap;
+ }
+ const double nLeftHeight (
+ rxBlock->maLeft.Paint(mxCanvas,
+ geometry::RealRectangle2D(
+ LeftX1,
+ nY,
+ LeftX2,
+ aWindowBox.Height - gnVerticalBorder),
+ false,
+ aViewState,
+ aRenderState,
+ mpFont->mxFont));
+ const double nRightHeight (
+ rxBlock->maRight.Paint(mxCanvas,
+ geometry::RealRectangle2D(
+ RightX1,
+ nY,
+ RightX2,
+ aWindowBox.Height - gnVerticalBorder),
+ true,
+ aViewState,
+ aRenderState,
+ mpFont->mxFont));
+
+ nY += ::std::max(nLeftHeight,nRightHeight);
+ }
+
+ Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
+ if (xSpriteCanvas.is())
+ xSpriteCanvas->updateScreen(false);
+}
+
+void PresenterHelpView::ReadHelpStrings()
+{
+ mpTextContainer.reset(new TextContainer);
+ PresenterConfigurationAccess aConfiguration (
+ mxComponentContext,
+ "/org.openoffice.Office.PresenterScreen/",
+ PresenterConfigurationAccess::READ_ONLY);
+ Reference<container::XNameAccess> xStrings (
+ aConfiguration.GetConfigurationNode("PresenterScreenSettings/HelpView/HelpStrings"),
+ UNO_QUERY);
+ PresenterConfigurationAccess::ForAll(
+ xStrings,
+ [this](OUString const&, uno::Reference<beans::XPropertySet> const& xProps)
+ {
+ return this->ProcessString(xProps);
+ });
+}
+
+void PresenterHelpView::ProcessString (
+ const Reference<beans::XPropertySet>& rsProperties)
+{
+ if ( ! rsProperties.is())
+ return;
+
+ OUString sLeftText;
+ PresenterConfigurationAccess::GetProperty(rsProperties, "Left") >>= sLeftText;
+ OUString sRightText;
+ PresenterConfigurationAccess::GetProperty(rsProperties, "Right") >>= sRightText;
+ mpTextContainer->push_back(
+ std::make_shared<Block>(
+ sLeftText, sRightText, mpFont->mxFont, mnMaximalWidth));
+}
+
+void PresenterHelpView::CheckFontSize()
+{
+ if (!mpFont)
+ return;
+
+ sal_Int32 nBestSize (6);
+
+ // Scaling down and then reformatting can cause the text to be too large
+ // still. So do this again and again until the text size is
+ // small enough. Restrict the number of loops.
+ for (int nLoopCount=0; nLoopCount<5; ++nLoopCount)
+ {
+ double nY = std::accumulate(mpTextContainer->begin(), mpTextContainer->end(), double(0),
+ [](const double& sum, const std::shared_ptr<Block>& rxBlock) {
+ return sum + std::max(
+ rxBlock->maLeft.GetHeight(),
+ rxBlock->maRight.GetHeight());
+ });
+
+ const double nHeightDifference (nY - (mnSeparatorY-gnVerticalBorder));
+ if (nHeightDifference <= 0 && nHeightDifference > -50)
+ {
+ // We have found a good font size that is large and leaves not
+ // too much space below the help text.
+ return;
+ }
+
+ // Use a simple linear transformation to calculate initial guess of
+ // a size that lets all help text be shown inside the window.
+ const double nScale (double(mnSeparatorY-gnVerticalBorder) / nY);
+ if (nScale > 1.0 && nScale < 1.05)
+ break;
+
+ sal_Int32 nFontSizeGuess (sal_Int32(mpFont->mnSize * nScale));
+ if (nHeightDifference<=0 && mpFont->mnSize>nBestSize)
+ nBestSize = mpFont->mnSize;
+ mpFont->mnSize = nFontSizeGuess;
+ mpFont->mxFont = nullptr;
+ mpFont->PrepareFont(mxCanvas);
+
+ // Reformat blocks.
+ for (auto& rxBlock : *mpTextContainer)
+ rxBlock->Update(mpFont->mxFont, mnMaximalWidth);
+ }
+
+ if (nBestSize != mpFont->mnSize)
+ {
+ mpFont->mnSize = nBestSize;
+ mpFont->mxFont = nullptr;
+ mpFont->PrepareFont(mxCanvas);
+
+ // Reformat blocks.
+ for (auto& rxBlock : *mpTextContainer)
+ {
+ rxBlock->Update(mpFont->mxFont, mnMaximalWidth);
+ }
+ }
+}
+
+//----- XResourceId -----------------------------------------------------------
+
+Reference<XResourceId> SAL_CALL PresenterHelpView::getResourceId()
+{
+ ThrowIfDisposed();
+ return mxViewId;
+}
+
+sal_Bool SAL_CALL PresenterHelpView::isAnchorOnly()
+{
+ return false;
+}
+
+
+void PresenterHelpView::ProvideCanvas()
+{
+ if ( ! mxCanvas.is() && mxPane.is())
+ {
+ mxCanvas = mxPane->getCanvas();
+ if ( ! mxCanvas.is())
+ return;
+ Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
+ if (xComponent.is())
+ xComponent->addEventListener(static_cast<awt::XPaintListener*>(this));
+
+ if (mpCloseButton.is())
+ mpCloseButton->SetCanvas(mxCanvas, mxWindow);
+ }
+}
+
+void PresenterHelpView::Resize()
+{
+ if (!(mpCloseButton && mxWindow.is()))
+ return;
+
+ const awt::Rectangle aWindowBox (mxWindow->getPosSize());
+ mnMaximalWidth = (mxWindow->getPosSize().Width - 4*gnHorizontalGap) / 2;
+
+ // Place vertical separator.
+ mnSeparatorY = aWindowBox.Height
+ - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
+
+ mpCloseButton->SetCenter(geometry::RealPoint2D(
+ aWindowBox.Width/2.0,
+ aWindowBox.Height - mpCloseButton->GetSize().Height/2.0));
+
+ CheckFontSize();
+}
+
+void PresenterHelpView::ThrowIfDisposed()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ {
+ throw lang::DisposedException (
+ "PresenterHelpView has been already disposed",
+ static_cast<uno::XWeak*>(this));
+ }
+}
+
+//===== LineDescriptor =========================================================
+
+namespace {
+
+LineDescriptor::LineDescriptor()
+ : maSize(0,0),
+ mnVerticalOffset(0)
+{
+}
+
+void LineDescriptor::AddPart (
+ std::u16string_view rsLine,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
+{
+ msLine += rsLine;
+
+ CalculateSize(rxFont);
+}
+
+bool LineDescriptor::IsEmpty() const
+{
+ return msLine.isEmpty();
+}
+
+void LineDescriptor::CalculateSize (
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont)
+{
+ OSL_ASSERT(rxFont.is());
+
+ rendering::StringContext aContext (msLine, 0, msLine.getLength());
+ Reference<rendering::XTextLayout> xLayout (
+ rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
+ const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
+ maSize = css::geometry::RealSize2D(aTextBBox.X2 - aTextBBox.X1, aTextBBox.Y2 - aTextBBox.Y1);
+ mnVerticalOffset = aTextBBox.Y2;
+}
+
+} // end of anonymous namespace
+
+//===== LineDescriptorList ====================================================
+
+namespace {
+
+LineDescriptorList::LineDescriptorList (
+ const OUString& rsText,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth)
+ : msText(rsText)
+{
+ Update(rxFont, nMaximalWidth);
+}
+
+double LineDescriptorList::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) const
+{
+ if ( ! rxCanvas.is())
+ return 0;
+
+ double nY (rBBox.Y1);
+ for (const auto& rLine : *mpLineDescriptors)
+ {
+ double nX;
+ /// check whether RTL interface or not
+ if(!AllSettings::GetLayoutRTL())
+ {
+ nX = rBBox.X1;
+ if ( ! bFlushLeft)
+ nX = rBBox.X2 - rLine.maSize.Width;
+ }
+ else
+ {
+ nX=rBBox.X2 - rLine.maSize.Width;
+ if ( ! bFlushLeft)
+ nX = rBBox.X1;
+ }
+ rRenderState.AffineTransform.m02 = nX;
+ rRenderState.AffineTransform.m12 = nY + rLine.maSize.Height - rLine.mnVerticalOffset;
+
+ const rendering::StringContext aContext (rLine.msLine, 0, rLine.msLine.getLength());
+ Reference<rendering::XTextLayout> xLayout (
+ rxFont->createTextLayout(aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
+ rxCanvas->drawTextLayout (
+ xLayout,
+ rViewState,
+ rRenderState);
+
+ nY += rLine.maSize.Height * 1.2;
+ }
+
+ return nY - rBBox.Y1;
+}
+
+double LineDescriptorList::GetHeight() const
+{
+ return std::accumulate(mpLineDescriptors->begin(), mpLineDescriptors->end(), double(0),
+ [](const double& nHeight, const LineDescriptor& rLine) {
+ return nHeight + rLine.maSize.Height * 1.2;
+ });
+}
+
+void LineDescriptorList::Update (
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth)
+{
+ vector<OUString> aTextParts;
+ SplitText(msText, aTextParts);
+ FormatText(aTextParts, rxFont, nMaximalWidth);
+}
+
+void LineDescriptorList::SplitText (
+ const OUString& rsText,
+ vector<OUString>& rTextParts)
+{
+ const char cQuote ('\'');
+ const char cSeparator (',');
+
+ sal_Int32 nIndex (0);
+ sal_Int32 nStart (0);
+ sal_Int32 nLength (rsText.getLength());
+ bool bIsQuoted (false);
+ while (nIndex < nLength)
+ {
+ const sal_Int32 nQuoteIndex (rsText.indexOf(cQuote, nIndex));
+ const sal_Int32 nSeparatorIndex (rsText.indexOf(cSeparator, nIndex));
+ if (nQuoteIndex>=0 && (nSeparatorIndex==-1 || nQuoteIndex<nSeparatorIndex))
+ {
+ bIsQuoted = !bIsQuoted;
+ nIndex = nQuoteIndex+1;
+ continue;
+ }
+
+ const sal_Int32 nNextIndex = nSeparatorIndex;
+ if (nNextIndex < 0)
+ {
+ break;
+ }
+ else if ( ! bIsQuoted)
+ {
+ rTextParts.push_back(rsText.copy(nStart, nNextIndex-nStart));
+ nStart = nNextIndex + 1;
+ }
+ nIndex = nNextIndex+1;
+ }
+ if (nStart < nLength)
+ rTextParts.push_back(rsText.copy(nStart, nLength-nStart));
+}
+
+void LineDescriptorList::FormatText (
+ const vector<OUString>& rTextParts,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth)
+{
+ LineDescriptor aLineDescriptor;
+
+ mpLineDescriptors = std::make_shared<vector<LineDescriptor>>();
+
+ vector<OUString>::const_iterator iPart (rTextParts.begin());
+ vector<OUString>::const_iterator iEnd (rTextParts.end());
+ while (iPart!=iEnd)
+ {
+ if (aLineDescriptor.IsEmpty())
+ {
+ // Avoid empty lines.
+ if (PresenterCanvasHelper::GetTextSize(
+ rxFont, *iPart).Width > nMaximalWidth)
+ {
+ const char cSpace (' ');
+
+ sal_Int32 nIndex (0);
+ sal_Int32 nStart (0);
+ sal_Int32 nLength (iPart->getLength());
+ while (nIndex < nLength)
+ {
+ sal_Int32 nSpaceIndex (iPart->indexOf(cSpace, nIndex));
+ while (nSpaceIndex >= 0 && PresenterCanvasHelper::GetTextSize(
+ rxFont, iPart->copy(nStart, nSpaceIndex-nStart)).Width <= nMaximalWidth)
+ {
+ nIndex = nSpaceIndex;
+ nSpaceIndex = iPart->indexOf(cSpace, nIndex+1);
+ }
+
+ if (nSpaceIndex < 0 && PresenterCanvasHelper::GetTextSize(
+ rxFont, iPart->copy(nStart, nLength-nStart)).Width <= nMaximalWidth)
+ {
+ nIndex = nLength;
+ }
+
+ if (nIndex == nStart)
+ {
+ nIndex = nLength;
+ }
+
+ aLineDescriptor.AddPart(iPart->subView(nStart, nIndex-nStart), rxFont);
+ if (nIndex != nLength)
+ {
+ mpLineDescriptors->push_back(aLineDescriptor);
+ aLineDescriptor = LineDescriptor();
+ }
+ nStart = nIndex;
+ }
+ }
+ else
+ {
+ aLineDescriptor.AddPart(*iPart, rxFont);
+ }
+ }
+ else if (PresenterCanvasHelper::GetTextSize(
+ rxFont, aLineDescriptor.msLine+", "+*iPart).Width > nMaximalWidth)
+ {
+ aLineDescriptor.AddPart(u",", rxFont);
+ mpLineDescriptors->push_back(aLineDescriptor);
+ aLineDescriptor = LineDescriptor();
+ continue;
+ }
+ else
+ {
+ aLineDescriptor.AddPart(OUStringConcatenation(", "+*iPart), rxFont);
+ }
+ ++iPart;
+ }
+ if ( ! aLineDescriptor.IsEmpty())
+ {
+ mpLineDescriptors->push_back(aLineDescriptor);
+ }
+}
+
+} // end of anonymous namespace
+
+//===== Block =================================================================
+
+namespace {
+
+Block::Block (
+ const OUString& rsLeftText,
+ const OUString& rsRightText,
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth)
+ : maLeft(rsLeftText, rxFont, nMaximalWidth),
+ maRight(rsRightText, rxFont, nMaximalWidth)
+{
+}
+
+void Block::Update (
+ const css::uno::Reference<css::rendering::XCanvasFont>& rxFont,
+ const sal_Int32 nMaximalWidth)
+{
+ maLeft.Update(rxFont, nMaximalWidth);
+ maRight.Update(rxFont, nMaximalWidth);
+}
+
+} // end of anonymous namespace
+
+} // end of namespace ::sdext::presenter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */