update dev300-m58
[ooovba.git] / sdext / source / presenter / PresenterClock.cxx
blobbf49c7a0431ce7299b4bd68d9da51a0fa9ad1d3b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: PresenterClock.cxx,v $
11 * $Revision: 1.6 $
13 * This file is part of OpenOffice.org.
15 * OpenOffice.org is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License version 3
17 * only, as published by the Free Software Foundation.
19 * OpenOffice.org is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License version 3 for more details
23 * (a copy is included in the LICENSE file that accompanied this code).
25 * You should have received a copy of the GNU Lesser General Public License
26 * version 3 along with OpenOffice.org. If not, see
27 * <http://www.openoffice.org/license.html>
28 * for a copy of the LGPLv3 License.
30 ************************************************************************/
32 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_sdext.hxx"
35 #include "PresenterClock.hxx"
36 #include "PresenterComponent.hxx"
37 #include "PresenterConfigurationAccess.hxx"
38 #include "PresenterGeometryHelper.hxx"
39 #include <com/sun/star/awt/InvalidateStyle.hpp>
40 #include <com/sun/star/awt/MouseButton.hpp>
41 #include <com/sun/star/awt/Point.hpp>
42 #include <com/sun/star/awt/XWindowPeer.hpp>
43 #include <com/sun/star/container/XNameAccess.hpp>
44 #include <com/sun/star/deployment/XPackageInformationProvider.hpp>
45 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
46 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
47 #include <com/sun/star/rendering/CompositeOperation.hpp>
48 #include <com/sun/star/rendering/PathCapType.hpp>
49 #include <com/sun/star/rendering/TextDirection.hpp>
50 #include <com/sun/star/rendering/XCanvasFont.hpp>
51 #include <com/sun/star/rendering/XSpriteCanvas.hpp>
52 #include <com/sun/star/util/Color.hpp>
53 #include <osl/mutex.hxx>
54 #include <osl/time.h>
55 #include <rtl/ref.hxx>
56 #include <vos/timer.hxx>
57 #include <boost/bind.hpp>
58 #include <cmath>
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::drawing::framework;
63 using ::rtl::OUString;
65 namespace sdext { namespace presenter {
68 /** Wrapper around a library timer.
70 class PresenterClock::Timer : public vos::OTimer
72 public:
73 explicit Timer (const ::rtl::Reference<PresenterClock>& rpClock);
74 virtual ~Timer (void);
76 void Stop (void);
78 protected:
79 virtual void SAL_CALL onShot (void);
81 private:
82 ::rtl::Reference<PresenterClock> mpClock;
88 namespace {
89 bool GetDateTime (oslDateTime& rDateTime);
91 class BitmapDescriptor
93 public:
94 Reference<rendering::XBitmap> mxBitmap;
95 awt::Point maOffset;
96 Reference<rendering::XBitmap> mxScaledBitmap;
97 geometry::RealPoint2D maScaledOffset;
104 class PresenterClock::Painter
106 public:
107 virtual void Paint (
108 const Reference<rendering::XCanvas>& rxCanvas,
109 const rendering::ViewState& rViewState,
110 const rendering::RenderState& rRenderState,
111 const util::Color& rBackgroundColor,
112 const sal_Int32 nHour,
113 const sal_Int32 nMinute,
114 const sal_Int32 nSecond,
115 const bool bShowSeconds) = 0;
116 virtual void Resize (const awt::Size& rSize) = 0;
122 namespace {
123 class AnalogDefaultPainter : public PresenterClock::Painter
125 public:
126 AnalogDefaultPainter (void);
127 virtual ~AnalogDefaultPainter (void) {}
128 virtual void Paint (
129 const Reference<rendering::XCanvas>& rxCanvas,
130 const rendering::ViewState& rViewState,
131 const rendering::RenderState& rRenderState,
132 const util::Color& rBackgroundColor,
133 const sal_Int32 nHour,
134 const sal_Int32 nMinute,
135 const sal_Int32 nSecond,
136 const bool bShowSeconds);
137 virtual void Resize (const awt::Size& rSize);
138 private:
139 geometry::RealPoint2D maCenter;
140 double mnOuterRadius;
141 awt::Size maSize;
142 Reference<rendering::XBitmap> mxBitmap;
144 /** Relative length (with respect to radius) from center to the tip of
145 the hand.
147 static const double mnRelativeHourHandLength;
148 /** Relative length (with respect to radius) from center to the
149 oposing end of the tip of the hand.
151 static const double mnRelativeHourHandLength2;
152 static const double mnRelativeHourHandWidth;
153 static const double mnRelativeMinuteHandLength;
154 static const double mnRelativeMinuteHandLength2;
155 static const double mnRelativeMinuteHandWidth;
156 static const double mnRelativeSecondHandLength;
157 static const double mnRelativeSecondHandLength2;
158 static const double mnRelativeSecondHandWidth;
160 void PaintAngledLine (
161 const double nAngle,
162 const double nInnerRadius,
163 const double nOuterRadius,
164 const double nStrokeWidth,
165 const Reference<rendering::XCanvas>& rxCanvas,
166 const rendering::ViewState& rViewState,
167 const rendering::RenderState& rRenderState);
171 class AnalogBitmapPainter : public PresenterClock::Painter
173 public:
174 AnalogBitmapPainter(
175 const Reference<XComponentContext>& rxContext,
176 const OUString& rsThemeName);
177 virtual ~AnalogBitmapPainter (void) {}
178 virtual void Paint (
179 const Reference<rendering::XCanvas>& rxCanvas,
180 const rendering::ViewState& rViewState,
181 const rendering::RenderState& rRenderState,
182 const util::Color& rBackgroundColor,
183 const sal_Int32 nHour,
184 const sal_Int32 nMinute,
185 const sal_Int32 nSecond,
186 const bool bShowSeconds);
187 virtual void Resize (const awt::Size& rSize);
188 private:
189 css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
190 const OUString msThemeName;
191 bool mbThemeLoaded;
192 bool mbThemeLoadingFailed;
193 geometry::RealPoint2D maCenter;
194 double mnOuterRadius;
195 BitmapDescriptor maFace;
196 BitmapDescriptor maMinuteHand;
197 BitmapDescriptor maHourHand;
199 void PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas);
200 Reference<container::XNameAccess> GetTheme (
201 PresenterConfigurationAccess& rConfiguration);
202 bool ThemeNameComparator (
203 const ::rtl::OUString& rsKey,
204 const Reference<container::XNameAccess>& rxCandidate,
205 const ::rtl::OUString& rsCurrentThemeName);
206 void LoadBitmaps (
207 PresenterConfigurationAccess& rConfiguration,
208 const Reference<container::XNameAccess>& rxNameAccess,
209 const Reference<rendering::XCanvas>& rxCanvas);
210 void LoadBitmap (
211 const OUString& rsKey,
212 const ::std::vector<Any>& rValues,
213 const OUString& rsBitmapPath,
214 const Reference<container::XNameAccess>& rxBitmapLoader);
215 void ScaleBitmaps (void);
219 class DigitalDefaultPainter : public PresenterClock::Painter
221 public:
222 DigitalDefaultPainter (
223 const ::rtl::Reference<PresenterController>& rpPresenterController,
224 const Reference<XResourceId>& rxViewId);
225 virtual ~DigitalDefaultPainter (void);
227 virtual void Paint (
228 const Reference<rendering::XCanvas>& rxCanvas,
229 const rendering::ViewState& rViewState,
230 const rendering::RenderState& rRenderState,
231 const util::Color& rBackgroundColor,
232 const sal_Int32 nHour,
233 const sal_Int32 nMinute,
234 const sal_Int32 nSecond,
235 const bool bShowSeconds);
236 virtual void Resize (const awt::Size& rSize);
238 private:
239 ::rtl::Reference<PresenterController> mpPresenterController;
240 bool mbIs24HourFormat;
241 bool mbIsAdaptFontSize;
242 Reference<rendering::XCanvasFont> mxFont;
243 awt::Size maWindowSize;
244 OUString msViewURL;
246 void CreateFont (
247 const Reference<rendering::XCanvas>& rxCanvas,
248 const bool bIsShowSeconds);
252 } // end of anonymous namespace
257 //===== PresenterClock =================================================================
259 ::rtl::Reference<PresenterClock> PresenterClock::Create (
260 const Reference<XComponentContext>& rxContext,
261 const Reference<XResourceId>& rxViewId,
262 const Reference<frame::XController>& rxController,
263 const ::rtl::Reference<PresenterController>& rpPresenterController)
265 ::rtl::Reference<PresenterClock> pClock (new PresenterClock(
266 rxContext,
267 rxViewId,
268 rxController,
269 rpPresenterController));
270 pClock->LateInit();
271 return pClock;
277 PresenterClock::PresenterClock (
278 const Reference<XComponentContext>& rxContext,
279 const Reference<XResourceId>& rxViewId,
280 const Reference<frame::XController>& rxController,
281 const ::rtl::Reference<PresenterController>& rpPresenterController)
282 : PresenterClockInterfaceBase(m_aMutex),
283 mxComponentContext(rxContext),
284 mxViewId(rxViewId),
285 mxWindow(),
286 mxCanvas(),
287 mxPane(),
288 mpPresenterController(rpPresenterController),
289 mbIsResizePending(true),
290 maViewState(),
291 maRenderState(),
292 mpTimer(),
293 mpClockPainter(),
294 mpClockPainter2(),
295 mnMode(1),
296 mnHour(-1),
297 mnMinute(-1),
298 mnSecond(-1),
299 mbIsShowSeconds(true)
301 SetMode(mnMode);
303 maViewState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0);
304 maRenderState.AffineTransform = geometry::AffineMatrix2D(1,0,0, 0,1,0);
305 maRenderState.DeviceColor = Sequence<double>(4);
306 PresenterCanvasHelper::SetDeviceColor(maRenderState, util::Color(0x00000000));
311 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
312 Reference<XConfigurationController> xCC (xCM->getConfigurationController(), UNO_QUERY_THROW);
313 mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
315 mxWindow = mxPane->getWindow();
316 if (mxWindow.is())
318 mxWindow->addPaintListener(this);
319 mxWindow->addWindowListener(this);
320 mxWindow->addMouseListener(this);
321 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
322 if (xPeer.is())
323 xPeer->setBackground(util::Color(0xff000000));
324 mxWindow->setVisible(sal_True);
327 Resize();
329 catch (RuntimeException&)
331 disposing();
332 throw;
339 PresenterClock::~PresenterClock (void)
346 void PresenterClock::LateInit (void)
348 mpTimer = new Timer(this);
354 void SAL_CALL PresenterClock::disposing (void)
356 // osl::MutexGuard aGuard (m_aMutex);
357 if (mpTimer != NULL)
359 mpTimer->Stop();
361 if (mxWindow.is())
363 mxWindow->removePaintListener(this);
364 mxWindow->removeWindowListener(this);
365 mxWindow->removeMouseListener(this);
366 mxWindow = NULL;
368 mxCanvas = NULL;
369 mxViewId = NULL;
375 void PresenterClock::UpdateTime (void)
377 // Get current time and check whether it is different from last time.
378 oslDateTime aDateTime;
379 if ( ! GetDateTime(aDateTime))
380 return;
381 if (aDateTime.Hours != mnHour
382 || aDateTime.Minutes != mnMinute
383 || aDateTime.Seconds != mnSecond)
385 mnHour = aDateTime.Hours % 24;
386 mnMinute = aDateTime.Minutes % 60;
387 mnSecond = aDateTime.Seconds % 60;
389 Reference<awt::XWindowPeer> xPeer (mxWindow, UNO_QUERY);
390 if (xPeer.is())
391 xPeer->invalidate(awt::InvalidateStyle::NOERASE |
392 awt::InvalidateStyle::UPDATE);
399 //----- lang::XEventListener -------------------------------------------------
401 void SAL_CALL PresenterClock::disposing (const lang::EventObject& rEventObject)
402 throw (RuntimeException)
404 // ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
405 // osl::MutexGuard aGuard (m_aMutex);
407 if (rEventObject.Source == mxWindow)
409 mxWindow = NULL;
410 if (mpTimer != NULL)
411 mpTimer->Stop();
418 //----- XPaintListener --------------------------------------------------------
420 void SAL_CALL PresenterClock::windowPaint (const awt::PaintEvent& rEvent)
421 throw (RuntimeException)
423 (void)rEvent;
424 ThrowIfDisposed();
425 ::osl::MutexGuard aSolarGuard (::osl::Mutex::getGlobalMutex());
426 Paint(rEvent.UpdateRect);
432 //----- XWindowListener -------------------------------------------------------
434 void SAL_CALL PresenterClock::windowResized (const awt::WindowEvent& rEvent)
435 throw (RuntimeException)
437 (void)rEvent;
438 mbIsResizePending = true;
444 void SAL_CALL PresenterClock::windowMoved (const awt::WindowEvent& rEvent)
445 throw (RuntimeException)
447 (void)rEvent;
448 mbIsResizePending = true;
454 void SAL_CALL PresenterClock::windowShown (const lang::EventObject& rEvent)
455 throw (RuntimeException)
457 (void)rEvent;
458 mbIsResizePending = true;
464 void SAL_CALL PresenterClock::windowHidden (const lang::EventObject& rEvent)
465 throw (RuntimeException)
467 (void)rEvent;
473 //----- XMouseListener --------------------------------------------------------
475 void SAL_CALL PresenterClock::mousePressed (const css::awt::MouseEvent& rEvent)
476 throw (css::uno::RuntimeException)
478 (void)rEvent;
479 if (rEvent.Buttons == awt::MouseButton::LEFT)
481 SetMode(mnMode+1);
488 void SAL_CALL PresenterClock::mouseReleased (const css::awt::MouseEvent& rEvent)
489 throw (css::uno::RuntimeException)
491 (void)rEvent;
497 void SAL_CALL PresenterClock::mouseEntered (const css::awt::MouseEvent& rEvent)
498 throw (css::uno::RuntimeException)
500 (void)rEvent;
506 void SAL_CALL PresenterClock::mouseExited (const css::awt::MouseEvent& rEvent)
507 throw (css::uno::RuntimeException)
509 (void)rEvent;
515 //----- XResourceId -----------------------------------------------------------
517 Reference<XResourceId> SAL_CALL PresenterClock::getResourceId (void)
518 throw (RuntimeException)
520 return mxViewId;
526 sal_Bool SAL_CALL PresenterClock::isAnchorOnly (void)
527 throw (RuntimeException)
529 return false;
535 //-----------------------------------------------------------------------------
537 void PresenterClock::Resize (void)
539 if (mxPane.is())
540 mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
541 if (mxWindow.is() && mxCanvas.is())
543 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
544 const awt::Size aWindowSize(aWindowBox.Width,aWindowBox.Height);
545 if (mpClockPainter.get() != NULL)
546 mpClockPainter->Resize(aWindowSize);
547 if (mpClockPainter2.get() != NULL)
548 mpClockPainter2->Resize(aWindowSize);
549 mbIsResizePending = false;
556 void PresenterClock::Paint (const awt::Rectangle& rUpdateBox)
558 if ( ! mxCanvas.is() && mxPane.is())
559 mxCanvas = Reference<rendering::XCanvas>(mxPane->getCanvas(), UNO_QUERY);
560 if ( ! mxWindow.is()
561 || ! mxCanvas.is()
562 || ! mxCanvas->getDevice().is())
564 return;
569 if (mbIsResizePending)
570 Resize();
572 Reference<rendering::XPolyPolygon2D> xUpdatePolygon (
573 PresenterGeometryHelper::CreatePolygon(rUpdateBox, mxCanvas->getDevice()));
575 Clear(xUpdatePolygon);
577 if (mpClockPainter.get() != NULL)
578 mpClockPainter->Paint(mxCanvas,
579 maViewState,
580 maRenderState,
581 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
582 mnHour,
583 mnMinute,
584 mnSecond,
585 mbIsShowSeconds);
587 if (mpClockPainter2.get() != NULL)
588 mpClockPainter2->Paint(
589 mxCanvas,
590 maViewState,
591 maRenderState,
592 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()),
593 mnHour,
594 mnMinute,
595 mnSecond,
596 mbIsShowSeconds);
598 catch (RuntimeException& e)
600 (void)e;
603 // Make the back buffer visible.
604 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
605 if (xSpriteCanvas.is())
606 xSpriteCanvas->updateScreen(sal_False);
612 void PresenterClock::Clear (const Reference<rendering::XPolyPolygon2D>& rxUpdatePolygon)
614 rendering::RenderState aRenderState = maRenderState;
615 const sal_Int32 nColor (
616 mpPresenterController->GetViewBackgroundColor(mxViewId->getResourceURL()));
617 aRenderState.DeviceColor[0] = ((nColor&0x00ff0000) >> 16) / 255.0;
618 aRenderState.DeviceColor[1] = ((nColor&0x0000ff00) >> 8) / 255.0;
619 aRenderState.DeviceColor[2] = ((nColor&0x000000ff) >> 0) / 255.0;
621 if (rxUpdatePolygon.is())
622 mxCanvas->fillPolyPolygon(
623 rxUpdatePolygon,
624 maViewState,
625 aRenderState);
631 void PresenterClock::SetMode (const sal_Int32 nMode)
633 mnMode = nMode % 3;
635 switch (mnMode)
637 case 0:
638 mpClockPainter.reset(
639 new AnalogBitmapPainter(
640 mxComponentContext,
641 OUString::createFromAscii("ClockTheme")));
642 mpClockPainter2.reset();
643 break;
645 case 1:
646 mpClockPainter.reset();
647 mpClockPainter2.reset(new AnalogDefaultPainter());
648 break;
650 case 2:
651 mpClockPainter.reset();
652 mpClockPainter2.reset(new DigitalDefaultPainter(mpPresenterController, mxViewId));
653 break;
655 case 3:
656 mpClockPainter.reset(
657 new AnalogBitmapPainter(
658 mxComponentContext,
659 OUString::createFromAscii("ClockTheme")));
660 mpClockPainter2.reset(new AnalogDefaultPainter());
661 break;
663 Resize();
669 void PresenterClock::ThrowIfDisposed (void)
670 throw (::com::sun::star::lang::DisposedException)
672 if (rBHelper.bDisposed || rBHelper.bInDispose)
674 throw lang::DisposedException (
675 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
676 "PresenterClock object has already been disposed")),
677 static_cast<uno::XWeak*>(this));
684 //===== Timer =================================================================
686 PresenterClock::Timer::Timer (const ::rtl::Reference<PresenterClock>& rpClock)
687 : OTimer(vos::TTimeValue(10), vos::TTimeValue(100/*ms*/)),
688 mpClock(rpClock)
690 acquire();
691 start();
697 PresenterClock::Timer::~Timer (void)
699 if (mpClock.is())
700 Stop();
706 void PresenterClock::Timer::Stop (void)
708 mpClock = NULL;
709 stop();
710 release();
716 void SAL_CALL PresenterClock::Timer::onShot (void)
718 if (mpClock.get() != NULL)
719 mpClock->UpdateTime();
724 namespace {
726 //=============================================================================
728 bool GetDateTime (oslDateTime& rDateTime)
730 TimeValue aSystemTime;
731 TimeValue aLocalTime;
732 if (osl_getSystemTime(&aSystemTime))
733 if (osl_getLocalTimeFromSystemTime(&aSystemTime, &aLocalTime))
734 if (osl_getDateTimeFromTimeValue(&aLocalTime, &rDateTime))
735 return true;
736 return false;
742 //===== AnalogDefaultPainter ==================================================
744 const double AnalogDefaultPainter::mnRelativeHourHandLength = 0.65;
745 const double AnalogDefaultPainter::mnRelativeHourHandLength2 (-0.1);
746 const double AnalogDefaultPainter::mnRelativeHourHandWidth (0.055);
747 const double AnalogDefaultPainter::mnRelativeMinuteHandLength (-0.2);
748 const double AnalogDefaultPainter::mnRelativeMinuteHandLength2 (0.85);
749 const double AnalogDefaultPainter::mnRelativeMinuteHandWidth (0.025);
750 const double AnalogDefaultPainter::mnRelativeSecondHandLength (-0.25);
751 const double AnalogDefaultPainter::mnRelativeSecondHandLength2 (0.95);
752 const double AnalogDefaultPainter::mnRelativeSecondHandWidth (0.015);
754 AnalogDefaultPainter::AnalogDefaultPainter (void)
755 : maCenter(0,0),
756 mnOuterRadius(0),
757 maSize(0,0),
758 mxBitmap()
765 void AnalogDefaultPainter::Paint (
766 const Reference<rendering::XCanvas>& rxCanvas,
767 const rendering::ViewState& rViewState,
768 const rendering::RenderState& rRenderState,
769 const util::Color& rBackgroundColor,
770 const sal_Int32 nHour,
771 const sal_Int32 nMinute,
772 const sal_Int32 nSecond,
773 const bool bShowSeconds)
775 double nInnerRadius (0);
776 double nStrokeWidth (0.1);
777 const double nClockSize (2*mnOuterRadius);
779 // Some antialiasing is created by painting into a bitmap twice the
780 // screen size and then scaling it down.
781 const sal_Int32 nSuperSampleFactor (2);
782 if ( ! mxBitmap.is())
784 mxBitmap = (rxCanvas->getDevice()->createCompatibleBitmap(
785 geometry::IntegerSize2D(
786 maSize.Width*nSuperSampleFactor,
787 maSize.Height*nSuperSampleFactor)));
789 Reference<rendering::XCanvas> xBitmapCanvas (mxBitmap, UNO_QUERY);
790 rendering::RenderState aRenderState(rRenderState);
791 aRenderState.AffineTransform.m00 = nSuperSampleFactor;
792 aRenderState.AffineTransform.m11 = nSuperSampleFactor;
794 // Clear the background.
795 aRenderState.DeviceColor[0] = ((rBackgroundColor&0x00ff0000) >> 16) / 255.0;
796 aRenderState.DeviceColor[1] = ((rBackgroundColor&0x0000ff00) >> 8) / 255.0;
797 aRenderState.DeviceColor[2] = ((rBackgroundColor&0x000000ff) >> 0) / 255.0;
798 Reference<rendering::XPolyPolygon2D> xPolygon (
799 PresenterGeometryHelper::CreatePolygon(
800 awt::Rectangle(0,0,maSize.Width,maSize.Height),
801 xBitmapCanvas->getDevice()));
802 if (xPolygon.is())
803 xBitmapCanvas->fillPolyPolygon(xPolygon, rViewState, aRenderState);
805 // Clock face and clock hands are painted in black.
806 aRenderState.DeviceColor[0] = 0;
807 aRenderState.DeviceColor[1] = 0;
808 aRenderState.DeviceColor[2] = 0;
810 // Paint the clock face.
811 for (sal_Int32 nHourMark=0; nHourMark<12; ++nHourMark)
813 if (nHourMark%3 == 0)
815 nInnerRadius = 0.7 * mnOuterRadius;
816 nStrokeWidth = 0.05 * nClockSize;
818 else
820 nInnerRadius = 0.8 * mnOuterRadius;
821 nStrokeWidth = 0.03 * nClockSize;
824 const double nAngle (nHourMark * 2 * M_PI / 12);
825 PaintAngledLine(nAngle, nInnerRadius, mnOuterRadius, nStrokeWidth,
826 xBitmapCanvas, rViewState, aRenderState);
829 // Paint the hour hand.
830 const double nHoursAngle (((nHour%12)+nMinute/60.0) * 2 * M_PI / 12);
831 PaintAngledLine(nHoursAngle,
832 mnRelativeHourHandLength2*mnOuterRadius,
833 mnRelativeHourHandLength*mnOuterRadius,
834 mnRelativeHourHandWidth*nClockSize,
835 xBitmapCanvas, rViewState, aRenderState);
837 // Paint the minute hand.
838 const double nMinutesAngle ((nMinute+nSecond/60.0) * 2 * M_PI / 60);
839 PaintAngledLine(nMinutesAngle,
840 mnRelativeMinuteHandLength2*mnOuterRadius,
841 mnRelativeMinuteHandLength*mnOuterRadius,
842 mnRelativeMinuteHandWidth*nClockSize,
843 xBitmapCanvas, rViewState, aRenderState);
845 // Optionally paint the second hand.
846 if (bShowSeconds)
848 const double nSecondsAngle (nSecond * 2 * M_PI / 60);
849 PaintAngledLine(nSecondsAngle,
850 mnRelativeSecondHandLength2*mnOuterRadius,
851 mnRelativeSecondHandLength*mnOuterRadius,
852 mnRelativeSecondHandWidth*nClockSize,
853 xBitmapCanvas, rViewState, aRenderState);
856 aRenderState.AffineTransform.m00 = 1.0 / nSuperSampleFactor;
857 aRenderState.AffineTransform.m11 = 1.0 / nSuperSampleFactor;
858 rxCanvas->drawBitmap(mxBitmap,rViewState,aRenderState);
864 void AnalogDefaultPainter::PaintAngledLine (
865 const double nAngle,
866 const double nInnerRadius,
867 const double nOuterRadius,
868 const double nStrokeWidth,
869 const Reference<rendering::XCanvas>& rxCanvas,
870 const rendering::ViewState& rViewState,
871 const rendering::RenderState& rRenderState)
873 if ( ! rxCanvas.is())
874 return;
876 rendering::StrokeAttributes aStrokeAttributes;
877 aStrokeAttributes.StrokeWidth = nStrokeWidth;
878 aStrokeAttributes.StartCapType = rendering::PathCapType::SQUARE;
879 aStrokeAttributes.EndCapType = rendering::PathCapType::SQUARE;
880 aStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
881 aStrokeAttributes.EndCapType = rendering::PathCapType::BUTT;
882 const double nCos (cos(nAngle - M_PI/2));
883 const double nSin (sin(nAngle - M_PI/2));
885 Sequence<Sequence<geometry::RealPoint2D> > aPoints(1);
886 aPoints[0] = Sequence<geometry::RealPoint2D>(2);
887 aPoints[0][0] = geometry::RealPoint2D(
888 maCenter.X + nInnerRadius*nCos + 0.5,
889 maCenter.Y + nInnerRadius*nSin + 0.5);
890 aPoints[0][1] = geometry::RealPoint2D(
891 maCenter.X + nOuterRadius*nCos + 0.5,
892 maCenter.Y + nOuterRadius*nSin + 0.5);
894 Reference<rendering::XPolyPolygon2D> xLine (
895 rxCanvas->getDevice()->createCompatibleLinePolyPolygon(aPoints),
896 UNO_QUERY);
897 if ( ! xLine.is())
898 return;
899 rxCanvas->strokePolyPolygon(
900 xLine,
901 rViewState,
902 rRenderState,
903 aStrokeAttributes);
909 void AnalogDefaultPainter::Resize (const awt::Size& rWindowSize)
911 maSize = rWindowSize;
912 maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
913 mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
914 mxBitmap = NULL;
920 //===== AnalogBitmapPainter ===================================================
922 AnalogBitmapPainter::AnalogBitmapPainter (
923 const Reference<XComponentContext>& rxContext,
924 const OUString& rsThemeName)
925 : mxComponentContext(rxContext),
926 msThemeName(rsThemeName),
927 mbThemeLoaded(false),
928 mbThemeLoadingFailed(false),
929 maCenter(),
930 mnOuterRadius(),
931 maFace(),
932 maMinuteHand(),
933 maHourHand()
940 void AnalogBitmapPainter::Paint (
941 const Reference<rendering::XCanvas>& rxCanvas,
942 const rendering::ViewState& rViewState,
943 const rendering::RenderState& rRenderState,
944 const util::Color& rBackgroundColor,
945 const sal_Int32 nHour,
946 const sal_Int32 nMinute,
947 const sal_Int32 nSecond,
948 const bool bShowSeconds)
950 (void)rBackgroundColor;
951 (void)nSecond;
952 (void)bShowSeconds;
954 if ( ! rxCanvas.is())
955 return;
957 rendering::RenderState aRenderState = rRenderState;
961 PrepareBitmaps(rxCanvas);
963 if (maFace.mxScaledBitmap.is())
965 aRenderState.AffineTransform = geometry::AffineMatrix2D(
966 1,0, maCenter.X - maFace.maScaledOffset.X,
967 0,1, maCenter.Y - maFace.maScaledOffset.Y);
968 rxCanvas->drawBitmap(maFace.mxScaledBitmap, rViewState, aRenderState);
971 if (maMinuteHand.mxScaledBitmap.is())
973 const double nMinuteAngle ((nMinute+nSecond/60.0) * 2.0 * M_PI / 60.0);
974 const double nCos (cos(nMinuteAngle - M_PI/2));
975 const double nSin (sin(nMinuteAngle - M_PI/2));
976 aRenderState.AffineTransform = geometry::AffineMatrix2D(
977 nCos,
978 -nSin,
979 -maMinuteHand.maScaledOffset.X*nCos
980 + maMinuteHand.maScaledOffset.Y*nSin+maCenter.X,
981 nSin,
982 nCos,
983 -maMinuteHand.maScaledOffset.X*nSin
984 - maMinuteHand.maScaledOffset.Y*nCos+maCenter.Y);
985 rxCanvas->drawBitmap(maMinuteHand.mxScaledBitmap, rViewState, aRenderState);
988 if (maHourHand.mxScaledBitmap.is())
990 const double nHoursAngle ((nHour%12+nMinute/60.0) * 2.0 * M_PI / 12.0);
991 const double nCos (cos(nHoursAngle - M_PI/2));
992 const double nSin (sin(nHoursAngle - M_PI/2));
993 aRenderState.AffineTransform = geometry::AffineMatrix2D(
994 nCos,
995 -nSin,
996 -maHourHand.maScaledOffset.X*nCos+maHourHand.maScaledOffset.Y*nSin+maCenter.X,
997 nSin,
998 nCos,
999 -maHourHand.maScaledOffset.X*nSin-maHourHand.maScaledOffset.Y*nCos+maCenter.Y);
1000 rxCanvas->drawBitmap(maHourHand.mxScaledBitmap, rViewState, aRenderState);
1003 catch(beans::UnknownPropertyException&)
1006 catch(RuntimeException&)
1014 void AnalogBitmapPainter::Resize (const awt::Size& rWindowSize)
1016 maCenter = geometry::RealPoint2D(rWindowSize.Width/2.0, rWindowSize.Height/2.0);
1017 mnOuterRadius = ::std::min(rWindowSize.Width, rWindowSize.Height) / 2.0 - 2;
1018 maFace.mxScaledBitmap = NULL;
1019 maHourHand.mxScaledBitmap = NULL;
1020 maMinuteHand.mxScaledBitmap = NULL;
1026 void AnalogBitmapPainter::PrepareBitmaps (const Reference<rendering::XCanvas>& rxCanvas)
1028 if (mbThemeLoadingFailed)
1030 // Theme loading has failed previously. Do not try a second time.
1031 return;
1033 if ( ! rxCanvas.is())
1035 // No canvas => bitmaps can neither be loaded, transformed into the
1036 // right format, nor can they be painted.
1037 return;
1040 if ( ! mbThemeLoaded)
1042 mbThemeLoaded = true;
1044 // Get access to the clock bitmaps in the configuration.
1045 PresenterConfigurationAccess aConfiguration (
1046 mxComponentContext,
1047 OUString::createFromAscii("org.openoffice.Office.extension.PresenterScreen"),
1048 PresenterConfigurationAccess::READ_ONLY);
1050 Reference<container::XNameAccess> xTheme (GetTheme(aConfiguration));
1051 if (xTheme.is())
1052 LoadBitmaps(aConfiguration, xTheme, rxCanvas);
1053 else
1054 mbThemeLoadingFailed = true;
1057 ScaleBitmaps();
1063 Reference<container::XNameAccess> AnalogBitmapPainter::GetTheme (
1064 PresenterConfigurationAccess& rConfiguration)
1066 Reference<container::XNameAccess> xTheme;
1068 // Get root of clock themes.
1069 Reference<container::XHierarchicalNameAccess> xClock (
1070 rConfiguration.GetConfigurationNode(
1071 OUString::createFromAscii("PresenterScreenSettings/AnalogBitmapClock")),
1072 UNO_QUERY);
1074 // Determine the name of the theme to use.
1075 OUString sCurrentThemeName (OUString::createFromAscii("DefaultTheme"));
1076 rConfiguration.GetConfigurationNode(
1077 xClock,
1078 OUString::createFromAscii("CurrentTheme")) >>= sCurrentThemeName;
1080 // Load the clock theme.
1081 Reference<container::XNameAccess> xThemes (
1082 rConfiguration.GetConfigurationNode(
1083 xClock,
1084 OUString::createFromAscii("Themes")),
1085 UNO_QUERY);
1086 if (xThemes.is())
1088 xTheme = Reference<container::XNameAccess>(
1089 PresenterConfigurationAccess::Find(
1090 xThemes,
1091 ::boost::bind(&AnalogBitmapPainter::ThemeNameComparator,
1092 this, _1, _2, sCurrentThemeName)),
1093 UNO_QUERY);
1096 return xTheme;
1102 bool AnalogBitmapPainter::ThemeNameComparator (
1103 const OUString& rsKey,
1104 const Reference<container::XNameAccess>& rxCandidate,
1105 const OUString& rsCurrentThemeName)
1107 (void)rsKey;
1108 if (rxCandidate.is())
1110 OUString sThemeName;
1111 if (rxCandidate->getByName(OUString::createFromAscii("ThemeName")) >>= sThemeName)
1113 return sThemeName == rsCurrentThemeName;
1116 return false;
1123 void AnalogBitmapPainter::LoadBitmaps (
1124 PresenterConfigurationAccess& rConfiguration,
1125 const Reference<container::XNameAccess>& rxClockTheme,
1126 const Reference<rendering::XCanvas>& rxCanvas)
1128 (void)rConfiguration;
1130 // Get base path to bitmaps.
1131 Reference<deployment::XPackageInformationProvider> xInformationProvider (
1132 mxComponentContext->getValueByName(OUString::createFromAscii(
1133 "/singletons/com.sun.star.deployment.PackageInformationProvider")),
1134 UNO_QUERY);
1135 OUString sLocation;
1136 if (xInformationProvider.is())
1137 sLocation = xInformationProvider->getPackageLocation(gsExtensionIdentifier);
1138 sLocation += OUString::createFromAscii("/");
1140 // Create the bitmap loader.
1141 Reference<lang::XMultiComponentFactory> xFactory (
1142 mxComponentContext->getServiceManager(), UNO_QUERY);
1143 if ( ! xFactory.is())
1144 return;
1145 Sequence<Any> aArguments(1);
1146 aArguments[0] <<= rxCanvas;
1147 Reference<container::XNameAccess> xBitmapLoader(
1148 xFactory->createInstanceWithArgumentsAndContext(
1149 OUString::createFromAscii("com.sun.star.drawing.PresenterWorkaroundService"),
1150 aArguments,
1151 mxComponentContext),
1152 UNO_QUERY);
1153 if ( ! xBitmapLoader.is())
1154 return;
1157 // Iterate over all entries in the bitmap list and load the bitmaps.
1158 Reference<container::XNameAccess> xBitmaps (
1159 rxClockTheme->getByName(OUString::createFromAscii("Bitmaps")),
1160 UNO_QUERY);
1161 ::std::vector<rtl::OUString> aBitmapProperties (3);
1162 aBitmapProperties[0] = OUString::createFromAscii("FileName");
1163 aBitmapProperties[1] = OUString::createFromAscii("XOffset");
1164 aBitmapProperties[2] = OUString::createFromAscii("YOffset");
1165 PresenterConfigurationAccess::ForAll(
1166 xBitmaps,
1167 aBitmapProperties,
1168 ::boost::bind(&AnalogBitmapPainter::LoadBitmap,
1169 this,
1172 sLocation,
1173 xBitmapLoader));
1179 void AnalogBitmapPainter::LoadBitmap (
1180 const OUString& rsKey,
1181 const ::std::vector<Any>& rValues,
1182 const OUString& rsBitmapPath,
1183 const Reference<container::XNameAccess>& rxBitmapLoader)
1185 if (rValues.size() == 3)
1187 BitmapDescriptor* pDescriptor = NULL;
1188 if (rsKey == OUString::createFromAscii("Face"))
1189 pDescriptor = &maFace;
1190 else if (rsKey == OUString::createFromAscii("HourHand"))
1191 pDescriptor = &maHourHand;
1192 else if (rsKey == OUString::createFromAscii("MinuteHand"))
1193 pDescriptor = &maMinuteHand;
1195 if (pDescriptor == NULL)
1196 return;
1198 OUString sFileName;
1199 if ( ! (rValues[0] >>= sFileName))
1200 return;
1202 rValues[1] >>= pDescriptor->maOffset.X;
1203 rValues[2] >>= pDescriptor->maOffset.Y;
1205 pDescriptor->mxBitmap = Reference<rendering::XBitmap>(
1206 rxBitmapLoader->getByName(rsBitmapPath+sFileName), UNO_QUERY);
1208 if ( ! pDescriptor->mxBitmap.is())
1209 mbThemeLoadingFailed = true;
1216 void AnalogBitmapPainter::ScaleBitmaps (void)
1218 if (mbThemeLoadingFailed)
1219 return;
1220 if ( ! maFace.mxBitmap.is())
1221 return;
1223 const geometry::IntegerSize2D aFaceSize (maFace.mxBitmap->getSize());
1224 const sal_Int32 nSize = std::max(aFaceSize.Width, aFaceSize.Height);
1225 const double nScale = mnOuterRadius*2 / nSize;
1227 BitmapDescriptor* aDescriptors[3] = { &maFace, &maHourHand, &maMinuteHand };
1228 for (int nIndex=0; nIndex<3; ++nIndex)
1230 BitmapDescriptor& rDescriptor (*aDescriptors[nIndex]);
1231 if ( ! rDescriptor.mxScaledBitmap.is() && rDescriptor.mxBitmap.is())
1233 const geometry::IntegerSize2D aBitmapSize (rDescriptor.mxBitmap->getSize());
1234 rDescriptor.mxScaledBitmap = rDescriptor.mxBitmap->getScaledBitmap(
1235 geometry::RealSize2D(aBitmapSize.Width*nScale, aBitmapSize.Height*nScale),
1236 sal_False);
1237 rDescriptor.maScaledOffset = geometry::RealPoint2D(
1238 rDescriptor.maOffset.X * nScale,
1239 rDescriptor.maOffset.Y * nScale);
1247 //===== DigitalDefaultPainter =================================================
1249 DigitalDefaultPainter::DigitalDefaultPainter (
1250 const ::rtl::Reference<PresenterController>& rpPresenterController,
1251 const Reference<XResourceId>& rxViewId)
1252 : mpPresenterController(rpPresenterController),
1253 mbIs24HourFormat(false),
1254 mbIsAdaptFontSize(true),
1255 mxFont(),
1256 maWindowSize(0,0),
1257 msViewURL(rxViewId.is() ? rxViewId->getResourceURL() : OUString())
1264 DigitalDefaultPainter::~DigitalDefaultPainter (void)
1271 void DigitalDefaultPainter::Paint (
1272 const Reference<rendering::XCanvas>& rxCanvas,
1273 const rendering::ViewState& rViewState,
1274 const rendering::RenderState& rRenderState,
1275 const util::Color& rBackgroundColor,
1276 const sal_Int32 nHour,
1277 const sal_Int32 nMinute,
1278 const sal_Int32 nSecond,
1279 const bool bIsShowSeconds)
1281 (void)rBackgroundColor;
1282 (void)rRenderState;
1284 if ( ! mxFont.is())
1285 CreateFont(rxCanvas,bIsShowSeconds);
1286 if ( ! mxFont.is())
1287 return;
1289 OUString sText;
1291 if (mbIs24HourFormat)
1292 sText = OUString::valueOf(nHour);
1293 else
1295 sText = OUString::valueOf(nHour>12 ? nHour-12 : nHour);
1297 sText += OUString::createFromAscii(":");
1298 const OUString sMinutes (OUString::valueOf(nMinute));
1299 switch (sMinutes.getLength())
1301 case 1 :
1302 sText += OUString::createFromAscii("0") + sMinutes;
1303 break;
1304 case 2:
1305 sText += sMinutes;
1306 break;
1308 default:
1309 return;
1311 if (bIsShowSeconds)
1313 sText += OUString::createFromAscii(":");
1314 const OUString sSeconds (OUString::valueOf(nSecond));
1315 switch (sSeconds.getLength())
1317 case 1 :
1318 sText += OUString::createFromAscii("0") + sSeconds;
1319 break;
1320 case 2:
1321 sText += sSeconds;
1322 break;
1324 default:
1325 return;
1329 rendering::StringContext aContext (
1330 sText,
1332 sText.getLength());
1333 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1334 aContext,
1335 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1336 0));
1337 if ( ! xLayout.is())
1338 return;
1339 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1342 rendering::RenderState aRenderState(
1343 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1344 NULL,
1345 Sequence<double>(4),
1346 rendering::CompositeOperation::SOURCE);
1348 util::Color aFontColor (mpPresenterController->GetViewFontColor(msViewURL));
1349 PresenterCanvasHelper::SetDeviceColor(aRenderState, aFontColor);
1350 aRenderState.AffineTransform.m02
1351 = (maWindowSize.Width - (aBox.X2-aBox.X1+1)) / 2 - aBox.X1;
1352 aRenderState.AffineTransform.m12
1353 = (maWindowSize.Height - (aBox.Y2-aBox.Y1+1)) / 2 - aBox.Y1;
1354 rxCanvas->drawText(
1355 aContext,
1356 mxFont,
1357 rViewState,
1358 aRenderState,
1359 rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1365 void DigitalDefaultPainter::Resize (const awt::Size& rSize)
1367 if (maWindowSize.Width != rSize.Width || maWindowSize.Height != rSize.Height)
1369 maWindowSize = rSize;
1370 if (mbIsAdaptFontSize)
1371 mxFont = NULL;
1378 void DigitalDefaultPainter::CreateFont (
1379 const Reference<rendering::XCanvas>& rxCanvas,
1380 const bool bIsShowSeconds)
1382 if (rxCanvas.is()
1383 && rxCanvas->getDevice().is()
1384 && maWindowSize.Width>0
1385 && maWindowSize.Height>0)
1387 // Create a time template for determinging the right font size.
1388 // Assume that 0 is the widest digit or that all digits have the
1389 // same width.
1390 OUString sTimeTemplate;
1391 // For the case that not all digits have the same width, create
1392 // different templates for 12 and 24 hour mode.
1393 if (mbIs24HourFormat)
1394 sTimeTemplate = OUString::createFromAscii("20");
1395 else
1396 sTimeTemplate = OUString::createFromAscii("10");
1397 if (bIsShowSeconds)
1398 sTimeTemplate += OUString::createFromAscii(":00:00");
1399 else
1400 sTimeTemplate += OUString::createFromAscii(":00");
1402 rendering::StringContext aContext (
1403 sTimeTemplate,
1405 sTimeTemplate.getLength());
1407 // When the font size is adapted to the window size (as large as
1408 // possible without overlapping) then that is done in a four step
1409 // process:
1410 // 1. Create a font in a default size, e.g. 10pt.
1411 // 2. Determine a scale factor from enlarging the text bounding box
1412 // to maximal size inside the window.
1413 // 3. Create a new font by scaling the default size with the factor
1414 // calculated in step 2.
1415 // 4. Text may be rendered differently in different sizes.
1416 // Therefore repeat step 2 and 3 once. More iterations may lead to
1417 // even better results but probably not to visible differences.
1418 rendering::FontRequest aFontRequest (mpPresenterController->GetViewFontRequest(msViewURL));
1419 // TODO: use font from view style from configuration
1420 aFontRequest.CellSize = 10;
1422 for (sal_Int32 nLoop=0; nLoop<3; ++nLoop)
1424 mxFont = rxCanvas->createFont(
1425 aFontRequest,
1426 Sequence<beans::PropertyValue>(),
1427 geometry::Matrix2D(1,0,0,1));
1428 if (mxFont.is())
1430 Reference<rendering::XTextLayout> xLayout (mxFont->createTextLayout(
1431 aContext,
1432 rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
1433 0));
1435 if ( ! xLayout.is())
1436 break;
1438 geometry::RealRectangle2D aBox (xLayout->queryTextBounds());
1439 if (aBox.X2<=aBox.X1 || aBox.Y2<=aBox.Y1)
1440 break;
1441 const double nHorizontalFactor = maWindowSize.Width / (aBox.X2-aBox.X1+1);
1442 const double nVerticalFactor = maWindowSize.Height / (aBox.Y2-aBox.Y1+1);
1443 aFontRequest.CellSize *= ::std::min(nHorizontalFactor,nVerticalFactor);
1450 } // end of anonymous namespace
1453 } } // end of namespace ::sdext::presenter