1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sdext.hxx"
26
27 #include "PresenterSlideSorter.hxx"
28 #include "PresenterButton.hxx"
29 #include "PresenterCanvasHelper.hxx"
30 #include "PresenterGeometryHelper.hxx"
31 #include "PresenterHelper.hxx"
32 #include "PresenterPaintManager.hxx"
33 #include "PresenterPaneBase.hxx"
34 #include "PresenterScrollBar.hxx"
35 #include "PresenterUIPainter.hxx"
36 #include "PresenterWindowManager.hxx"
37 #include <com/sun/star/awt/PosSize.hpp>
38 #include <com/sun/star/awt/XWindowPeer.hpp>
39 #include <com/sun/star/container/XNameAccess.hpp>
40 #include <com/sun/star/container/XNamed.hpp>
41 #include <com/sun/star/drawing/XSlideSorterBase.hpp>
42 #include <com/sun/star/drawing/framework/XConfigurationController.hpp>
43 #include <com/sun/star/drawing/framework/XControllerManager.hpp>
44 #include <com/sun/star/rendering/CompositeOperation.hpp>
45 #include <com/sun/star/rendering/TextDirection.hpp>
46 #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
47 #include <com/sun/star/util/Color.hpp>
48 #include <algorithm>
49 #include <math.h>
50 #include <boost/bind.hpp>
51
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::drawing::framework;
55 using ::rtl::OUString;
56
57 #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
58
59 namespace {
60 const static sal_Int32 gnVerticalGap (10);
61 const static sal_Int32 gnVerticalBorder (10);
62 const static sal_Int32 gnHorizontalGap (10);
63 const static sal_Int32 gnHorizontalBorder (10);
64
65 const static double gnMinimalPreviewWidth (200);
66 const static double gnPreferredPreviewWidth (300);
67 const static double gnMaximalPreviewWidth (400);
68 const static sal_Int32 gnPreferredColumnCount (6);
69 const static double gnMinimalHorizontalPreviewGap(15);
70 const static double gnPreferredHorizontalPreviewGap(25);
71 const static double gnMaximalHorizontalPreviewGap(50);
72 const static double gnMinimalVerticalPreviewGap(15);
73 const static double gnPreferredVerticalPreviewGap(25);
74 const static double gnMaximalVerticalPreviewGap(50);
75
76 const static sal_Int32 gnHorizontalLabelBorder (3);
77 const static sal_Int32 gnHorizontalLabelPadding (5);
78
79 const static sal_Int32 gnVerticalButtonPadding (gnVerticalGap);
80 }
81
82 namespace sdext { namespace presenter {
83
84 namespace {
round(const double nValue)85 sal_Int32 round (const double nValue) { return sal::static_int_cast<sal_Int32>(0.5 + nValue); }
floor(const double nValue)86 sal_Int32 floor (const double nValue) { return sal::static_int_cast<sal_Int32>(nValue); }
87 }
88
89
90
91 //===== PresenterSlideSorter::Layout ==========================================
92
93 class PresenterSlideSorter::Layout
94 {
95 public:
96 enum Orientation { Horizontal, Vertical };
97 Layout (
98 const Orientation eOrientation,
99 const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar,
100 const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar);
101
102 void Update (const geometry::RealRectangle2D& rBoundingBox, const double nSlideAspectRatio);
103 void SetupVisibleArea (void);
104 void UpdateScrollBars (void);
105 bool IsScrollBarNeeded (const sal_Int32 nSlideCount);
106 geometry::RealPoint2D GetLocalPosition (const geometry::RealPoint2D& rWindowPoint) const;
107 geometry::RealPoint2D GetWindowPosition(const geometry::RealPoint2D& rLocalPoint) const;
108 sal_Int32 GetColumn (const geometry::RealPoint2D& rLocalPoint,
109 const bool bReturnInvalidValue = false) const;
110 sal_Int32 GetRow (const geometry::RealPoint2D& rLocalPoint,
111 const bool bReturnInvalidValue = false) const;
112 sal_Int32 GetSlideIndexForPosition (const css::geometry::RealPoint2D& rPoint) const;
113 css::geometry::RealPoint2D GetPoint (
114 const sal_Int32 nSlideIndex,
115 const sal_Int32 nRelativeHorizontalPosition,
116 const sal_Int32 nRelativeVerticalPosition) const;
117 css::awt::Rectangle GetBoundingBox (const sal_Int32 nSlideIndex) const;
118 void ForAllVisibleSlides (const ::boost::function<void(sal_Int32)>& rAction);
119 sal_Int32 GetFirstVisibleSlideIndex (void) const;
120 sal_Int32 GetLastVisibleSlideIndex (void) const;
121 bool SetHorizontalOffset (const double nOffset);
122 bool SetVerticalOffset (const double nOffset);
123 Orientation GetOrientation (void) const;
124
125 css::geometry::RealRectangle2D maBoundingBox;
126 css::geometry::IntegerSize2D maPreviewSize;
127 sal_Int32 mnHorizontalOffset;
128 sal_Int32 mnVerticalOffset;
129 sal_Int32 mnHorizontalGap;
130 sal_Int32 mnVerticalGap;
131 sal_Int32 mnHorizontalBorder;
132 sal_Int32 mnVerticalBorder;
133 sal_Int32 mnRowCount;
134 sal_Int32 mnColumnCount;
135 sal_Int32 mnSlideCount;
136 sal_Int32 mnSlideIndexAtMouse;
137 sal_Int32 mnFirstVisibleColumn;
138 sal_Int32 mnLastVisibleColumn;
139 sal_Int32 mnFirstVisibleRow;
140 sal_Int32 mnLastVisibleRow;
141
142 private:
143 Orientation meOrientation;
144 ::rtl::Reference<PresenterScrollBar> mpHorizontalScrollBar;
145 ::rtl::Reference<PresenterScrollBar> mpVerticalScrollBar;
146
147 sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const;
148 sal_Int32 GetRow (const sal_Int32 nSlideIndex) const;
149 sal_Int32 GetColumn (const sal_Int32 nSlideIndex) const;
150 };
151
152
153
154
155 //==== PresenterSlideSorter::MouseOverManager =================================
156
157 class PresenterSlideSorter::MouseOverManager
158 : ::boost::noncopyable
159 {
160 public:
161 MouseOverManager (
162 const Reference<container::XIndexAccess>& rxSlides,
163 const ::boost::shared_ptr<PresenterTheme>& rpTheme,
164 const Reference<awt::XWindow>& rxInvalidateTarget,
165 const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager);
166 ~MouseOverManager (void);
167
168 void Paint (
169 const sal_Int32 nSlideIndex,
170 const Reference<rendering::XCanvas>& rxCanvas,
171 const Reference<rendering::XPolyPolygon2D>& rxClip);
172
173 void SetSlide (
174 const sal_Int32 nSlideIndex,
175 const awt::Rectangle& rBox);
176
177 private:
178 Reference<rendering::XCanvas> mxCanvas;
179 const Reference<container::XIndexAccess> mxSlides;
180 SharedBitmapDescriptor mpLeftLabelBitmap;
181 SharedBitmapDescriptor mpCenterLabelBitmap;
182 SharedBitmapDescriptor mpRightLabelBitmap;
183 PresenterTheme::SharedFontDescriptor mpFont;
184 sal_Int32 mnSlideIndex;
185 awt::Rectangle maSlideBoundingBox;
186 OUString msText;
187 Reference<rendering::XBitmap> mxBitmap;
188 Reference<awt::XWindow> mxInvalidateTarget;
189 ::boost::shared_ptr<PresenterPaintManager> mpPaintManager;
190
191 void SetCanvas (
192 const Reference<rendering::XCanvas>& rxCanvas);
193 /** Create a bitmap that shows the given text and is not wider than the
194 given maximal width.
195 */
196 Reference<rendering::XBitmap> CreateBitmap (
197 const OUString& rsText,
198 const sal_Int32 nMaximalWidth) const;
199 void Invalidate (void);
200 geometry::IntegerSize2D CalculateLabelSize (
201 const OUString& rsText) const;
202 OUString GetFittingText (const OUString& rsText, const double nMaximalWidth) const;
203 void PaintButtonBackground (
204 const Reference<rendering::XBitmapCanvas>& rxCanvas,
205 const geometry::IntegerSize2D& rSize) const;
206 };
207
208
209
210
211 //==== PresenterSlideSorter::CurrentSlideFrameRenderer ========================
212
213 class PresenterSlideSorter::CurrentSlideFrameRenderer
214 {
215 public:
216 CurrentSlideFrameRenderer (
217 const css::uno::Reference<css::uno::XComponentContext>& rxContext,
218 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas);
219 ~CurrentSlideFrameRenderer (void);
220
221 void PaintCurrentSlideFrame (
222 const awt::Rectangle& rSlideBoundingBox,
223 const Reference<rendering::XCanvas>& rxCanvas,
224 const geometry::RealRectangle2D& rClipBox);
225
226 /** Enlarge the given rectangle to include the current slide indicator.
227 */
228 awt::Rectangle GetBoundingBox (
229 const awt::Rectangle& rSlideBoundingBox);
230
231 private:
232 SharedBitmapDescriptor mpTopLeft;
233 SharedBitmapDescriptor mpTop;
234 SharedBitmapDescriptor mpTopRight;
235 SharedBitmapDescriptor mpLeft;
236 SharedBitmapDescriptor mpRight;
237 SharedBitmapDescriptor mpBottomLeft;
238 SharedBitmapDescriptor mpBottom;
239 SharedBitmapDescriptor mpBottomRight;
240 sal_Int32 mnTopFrameSize;
241 sal_Int32 mnLeftFrameSize;
242 sal_Int32 mnRightFrameSize;
243 sal_Int32 mnBottomFrameSize;
244
245 void PaintBitmapOnce(
246 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
247 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
248 const Reference<rendering::XPolyPolygon2D>& rxClip,
249 const double nX,
250 const double nY);
251 void PaintBitmapTiled(
252 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
253 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
254 const geometry::RealRectangle2D& rClipBox,
255 const double nX,
256 const double nY,
257 const double nWidth,
258 const double nHeight);
259 };
260
261
262
263
264 //===== PresenterSlideSorter ==================================================
265
PresenterSlideSorter(const Reference<uno::XComponentContext> & rxContext,const Reference<XResourceId> & rxViewId,const Reference<frame::XController> & rxController,const::rtl::Reference<PresenterController> & rpPresenterController)266 PresenterSlideSorter::PresenterSlideSorter (
267 const Reference<uno::XComponentContext>& rxContext,
268 const Reference<XResourceId>& rxViewId,
269 const Reference<frame::XController>& rxController,
270 const ::rtl::Reference<PresenterController>& rpPresenterController)
271 : PresenterSlideSorterInterfaceBase(m_aMutex),
272 mxComponentContext(rxContext),
273 mxViewId(rxViewId),
274 mxPane(),
275 mxCanvas(),
276 mxWindow(),
277 mpPresenterController(rpPresenterController),
278 mxSlideShowController(mpPresenterController->GetSlideShowController()),
279 mxPreviewCache(),
280 mbIsPaintPending(true),
281 mbIsLayoutPending(true),
282 mpLayout(),
283 mpHorizontalScrollBar(),
284 mpVerticalScrollBar(),
285 mpCloseButton(),
286 mpMouseOverManager(),
287 mnSlideIndexMousePressed(-1),
288 mnCurrentSlideIndex(-1),
289 mnSeparatorY(0),
290 maSeparatorColor(0x00ffffff),
291 maCloseButtonCenter(),
292 maCurrentSlideFrameBoundingBox(),
293 mpCurrentSlideFrameRenderer(),
294 mxPreviewFrame()
295 {
296 if ( ! rxContext.is()
297 || ! rxViewId.is()
298 || ! rxController.is()
299 || rpPresenterController.get()==NULL)
300 {
301 throw lang::IllegalArgumentException();
302 }
303
304 if ( ! mxSlideShowController.is())
305 throw RuntimeException();
306
307 try
308 {
309 // Get pane and window.
310 Reference<XControllerManager> xCM (rxController, UNO_QUERY_THROW);
311 Reference<XConfigurationController> xCC (
312 xCM->getConfigurationController(), UNO_QUERY_THROW);
313 Reference<lang::XMultiComponentFactory> xFactory (
314 mxComponentContext->getServiceManager(), UNO_QUERY_THROW);
315
316 mxPane = Reference<XPane>(xCC->getResource(rxViewId->getAnchor()), UNO_QUERY_THROW);
317 mxWindow = mxPane->getWindow();
318
319 // Add window listener.
320 mxWindow->addWindowListener(this);
321 mxWindow->addPaintListener(this);
322 mxWindow->addMouseListener(this);
323 mxWindow->addMouseMotionListener(this);
324 mxWindow->setVisible(sal_True);
325
326 // Remember the current slide.
327 mnCurrentSlideIndex = mxSlideShowController->getCurrentSlideIndex();
328
329 // Set the orientation.
330 const bool bIsVertical (true);
331
332 // Create the scroll bar.
333 if (bIsVertical)
334 mpVerticalScrollBar = ::rtl::Reference<PresenterScrollBar>(
335 new PresenterVerticalScrollBar(
336 rxContext,
337 mxWindow,
338 mpPresenterController->GetPaintManager(),
339 ::boost::bind(&PresenterSlideSorter::SetVerticalOffset,this,_1)));
340 else
341 mpHorizontalScrollBar = ::rtl::Reference<PresenterScrollBar>(
342 new PresenterHorizontalScrollBar(
343 rxContext,
344 mxWindow,
345 mpPresenterController->GetPaintManager(),
346 ::boost::bind(&PresenterSlideSorter::SetHorizontalOffset,this,_1)));
347 mpCloseButton = PresenterButton::Create(
348 rxContext,
349 mpPresenterController,
350 mpPresenterController->GetTheme(),
351 mxWindow,
352 mxCanvas,
353 A2S("SlideSorterCloser"));
354
355 if (mpPresenterController->GetTheme().get() != NULL)
356 {
357 PresenterTheme::SharedFontDescriptor pFont (
358 mpPresenterController->GetTheme()->GetFont(A2S("ButtonFont")));
359 if (pFont.get() != NULL)
360 maSeparatorColor = pFont->mnColor;
361 }
362
363 // Create the layout.
364 mpLayout.reset(new Layout(
365 Layout::Vertical,
366 mpHorizontalScrollBar,
367 mpVerticalScrollBar));
368
369 // Create the preview cache.
370 mxPreviewCache = Reference<drawing::XSlidePreviewCache>(
371 xFactory->createInstanceWithContext(
372 OUString::createFromAscii("com.sun.star.drawing.PresenterPreviewCache"),
373 mxComponentContext),
374 UNO_QUERY_THROW);
375 Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY);
376 mxPreviewCache->setDocumentSlides(xSlides, rxController->getModel());
377 mxPreviewCache->addPreviewCreationNotifyListener(this);
378 if (xSlides.is())
379 {
380 mpLayout->mnSlideCount = xSlides->getCount();
381 }
382
383 // Create the mouse over manager.
384 mpMouseOverManager.reset(new MouseOverManager(
385 Reference<container::XIndexAccess>(mxSlideShowController, UNO_QUERY),
386 mpPresenterController->GetTheme(),
387 mxWindow,
388 mpPresenterController->GetPaintManager()));
389
390 // Listen for changes of the current slide.
391 Reference<beans::XPropertySet> xControllerProperties (rxController, UNO_QUERY_THROW);
392 xControllerProperties->addPropertyChangeListener(
393 OUString::createFromAscii("CurrentPage"),
394 this);
395
396 // Move the current slide in the center of the window.
397 const awt::Rectangle aCurrentSlideBBox (mpLayout->GetBoundingBox(mnCurrentSlideIndex));
398 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
399 SetHorizontalOffset(aCurrentSlideBBox.X - aWindowBox.Width/2.0);
400 }
401 catch (RuntimeException&)
402 {
403 disposing();
404 throw;
405 }
406 }
407
408
409
410
~PresenterSlideSorter(void)411 PresenterSlideSorter::~PresenterSlideSorter (void)
412 {
413 }
414
415
416
417
disposing(void)418 void SAL_CALL PresenterSlideSorter::disposing (void)
419 {
420 mxComponentContext = NULL;
421 mxViewId = NULL;
422 mxPane = NULL;
423
424 if (mpVerticalScrollBar.is())
425 {
426 Reference<lang::XComponent> xComponent (
427 static_cast<XWeak*>(mpVerticalScrollBar.get()), UNO_QUERY);
428 mpVerticalScrollBar = NULL;
429 if (xComponent.is())
430 xComponent->dispose();
431 }
432 if (mpHorizontalScrollBar.is())
433 {
434 Reference<lang::XComponent> xComponent (
435 static_cast<XWeak*>(mpHorizontalScrollBar.get()), UNO_QUERY);
436 mpHorizontalScrollBar = NULL;
437 if (xComponent.is())
438 xComponent->dispose();
439 }
440 if (mpCloseButton.is())
441 {
442 Reference<lang::XComponent> xComponent (
443 static_cast<XWeak*>(mpCloseButton.get()), UNO_QUERY);
444 mpCloseButton = NULL;
445 if (xComponent.is())
446 xComponent->dispose();
447 }
448
449 if (mxCanvas.is())
450 {
451 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
452 if (xComponent.is())
453 xComponent->removeEventListener(static_cast<awt::XWindowListener*>(this));
454 mxCanvas = NULL;
455 }
456 mpPresenterController = NULL;
457 mxSlideShowController = NULL;
458 mpLayout.reset();
459 mpMouseOverManager.reset();
460
461 if (mxPreviewCache.is())
462 {
463 mxPreviewCache->removePreviewCreationNotifyListener(this);
464
465 Reference<XComponent> xComponent (mxPreviewCache, UNO_QUERY);
466 mxPreviewCache = NULL;
467 if (xComponent.is())
468 xComponent->dispose();
469 }
470
471 if (mxWindow.is())
472 {
473 mxWindow->removeWindowListener(this);
474 mxWindow->removePaintListener(this);
475 mxWindow->removeMouseListener(this);
476 mxWindow->removeMouseMotionListener(this);
477 }
478 }
479
480
481
482
SetActiveState(const bool bIsActive)483 void PresenterSlideSorter::SetActiveState (const bool bIsActive)
484 {
485 (void)bIsActive;
486 }
487
488
489
490
491 //----- lang::XEventListener --------------------------------------------------
492
disposing(const lang::EventObject & rEventObject)493 void SAL_CALL PresenterSlideSorter::disposing (const lang::EventObject& rEventObject)
494 throw (RuntimeException)
495 {
496 if (rEventObject.Source == mxWindow)
497 {
498 mxWindow = NULL;
499 dispose();
500 }
501 else if (rEventObject.Source == mxPreviewCache)
502 {
503 mxPreviewCache = NULL;
504 dispose();
505 }
506 else if (rEventObject.Source == mxCanvas)
507 {
508 mxCanvas = NULL;
509 if (mpHorizontalScrollBar.is())
510 mpHorizontalScrollBar->SetCanvas(NULL);
511 mbIsLayoutPending = true;
512 mbIsPaintPending = true;
513
514 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
515 }
516 }
517
518
519
520
521 //----- XWindowListener -------------------------------------------------------
522
windowResized(const awt::WindowEvent & rEvent)523 void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent& rEvent)
524 throw (uno::RuntimeException)
525 {
526 (void)rEvent;
527 ThrowIfDisposed();
528 mbIsLayoutPending = true;
529 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
530 }
531
532
533
534
windowMoved(const awt::WindowEvent & rEvent)535 void SAL_CALL PresenterSlideSorter::windowMoved (const awt::WindowEvent& rEvent)
536 throw (uno::RuntimeException)
537 {
538 (void)rEvent;
539 ThrowIfDisposed();
540 }
541
542
543
544
windowShown(const lang::EventObject & rEvent)545 void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject& rEvent)
546 throw (uno::RuntimeException)
547 {
548 (void)rEvent;
549 ThrowIfDisposed();
550 mbIsLayoutPending = true;
551 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
552 }
553
554
555
556
windowHidden(const lang::EventObject & rEvent)557 void SAL_CALL PresenterSlideSorter::windowHidden (const lang::EventObject& rEvent)
558 throw (uno::RuntimeException)
559 {
560 (void)rEvent;
561 ThrowIfDisposed();
562 }
563
564
565
566
567 //----- XPaintListener --------------------------------------------------------
568
windowPaint(const css::awt::PaintEvent & rEvent)569 void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent)
570 throw (RuntimeException)
571 {
572 (void)rEvent;
573
574 // Deactivated views must not be painted.
575 if ( ! mbIsPresenterViewActive)
576 return;
577
578 Paint(rEvent.UpdateRect);
579
580 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
581 if (xSpriteCanvas.is())
582 xSpriteCanvas->updateScreen(sal_False);
583 }
584
585
586
587
588 //----- XMouseListener --------------------------------------------------------
589
mousePressed(const css::awt::MouseEvent & rEvent)590 void SAL_CALL PresenterSlideSorter::mousePressed (const css::awt::MouseEvent& rEvent)
591 throw(css::uno::RuntimeException)
592 {
593 const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y);
594 mnSlideIndexMousePressed = mpLayout->GetSlideIndexForPosition(aPosition);
595 }
596
597
598
599
mouseReleased(const css::awt::MouseEvent & rEvent)600 void SAL_CALL PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent& rEvent)
601 throw(css::uno::RuntimeException)
602 {
603 const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y);
604 const sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
605
606 if (nSlideIndex == mnSlideIndexMousePressed && mnSlideIndexMousePressed >= 0)
607 {
608 switch (rEvent.ClickCount)
609 {
610 case 1:
611 default:
612 GotoSlide(nSlideIndex);
613 break;
614
615 case 2:
616 OSL_ASSERT(mpPresenterController.get()!=NULL);
617 OSL_ASSERT(mpPresenterController->GetWindowManager().get()!=NULL);
618 mpPresenterController->GetWindowManager()->SetSlideSorterState(false);
619 GotoSlide(nSlideIndex);
620 break;
621 }
622 }
623 }
624
625
626
627
mouseEntered(const css::awt::MouseEvent & rEvent)628 void SAL_CALL PresenterSlideSorter::mouseEntered (const css::awt::MouseEvent& rEvent)
629 throw(css::uno::RuntimeException)
630 {
631 (void)rEvent;
632 }
633
634
635
636
mouseExited(const css::awt::MouseEvent & rEvent)637 void SAL_CALL PresenterSlideSorter::mouseExited (const css::awt::MouseEvent& rEvent)
638 throw(css::uno::RuntimeException)
639 {
640 (void)rEvent;
641 mnSlideIndexMousePressed = -1;
642 if (mpMouseOverManager.get() != NULL)
643 mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0));
644 }
645
646
647
648
649 //----- XMouseMotionListener --------------------------------------------------
650
mouseMoved(const css::awt::MouseEvent & rEvent)651 void SAL_CALL PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent& rEvent)
652 throw (css::uno::RuntimeException)
653 {
654 if (mpMouseOverManager.get() != NULL)
655 {
656 const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y);
657 sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
658
659 if (nSlideIndex < 0)
660 mnSlideIndexMousePressed = -1;
661
662 if (nSlideIndex < 0)
663 {
664 mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0));
665 }
666 else
667 {
668 mpMouseOverManager->SetSlide(
669 nSlideIndex,
670 mpLayout->GetBoundingBox(nSlideIndex));
671 }
672 }
673 }
674
675
676
677
mouseDragged(const css::awt::MouseEvent & rEvent)678 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent& rEvent)
679 throw (css::uno::RuntimeException)
680 {
681 (void)rEvent;
682 }
683
684
685
686
687 //----- XResourceId -----------------------------------------------------------
688
getResourceId(void)689 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId (void)
690 throw (RuntimeException)
691 {
692 ThrowIfDisposed();
693 return mxViewId;
694 }
695
696
697
698
isAnchorOnly(void)699 sal_Bool SAL_CALL PresenterSlideSorter::isAnchorOnly (void)
700 throw (RuntimeException)
701 {
702 return false;
703 }
704
705
706
707
708 //----- XPropertyChangeListener -----------------------------------------------
709
propertyChange(const css::beans::PropertyChangeEvent & rEvent)710 void SAL_CALL PresenterSlideSorter::propertyChange (
711 const css::beans::PropertyChangeEvent& rEvent)
712 throw(css::uno::RuntimeException)
713 {
714 (void)rEvent;
715 }
716
717
718
719
720 //----- XSlidePreviewCacheListener --------------------------------------------
721
notifyPreviewCreation(sal_Int32 nSlideIndex)722 void SAL_CALL PresenterSlideSorter::notifyPreviewCreation (
723 sal_Int32 nSlideIndex)
724 throw(css::uno::RuntimeException)
725 {
726 OSL_ASSERT(mpLayout.get()!=NULL);
727
728 awt::Rectangle aBBox (mpLayout->GetBoundingBox(nSlideIndex));
729 mpPresenterController->GetPaintManager()->Invalidate(mxWindow, aBBox, true);
730 }
731
732
733
734
735 //----- XDrawView -------------------------------------------------------------
736
setCurrentPage(const Reference<drawing::XDrawPage> & rxSlide)737 void SAL_CALL PresenterSlideSorter::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
738 throw (RuntimeException)
739 {
740 (void)rxSlide;
741
742 ThrowIfDisposed();
743 ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
744
745 if (mxSlideShowController.is())
746 {
747 const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex());
748 if (nNewCurrentSlideIndex != mnCurrentSlideIndex)
749 {
750 mnCurrentSlideIndex = nNewCurrentSlideIndex;
751
752 // Request a repaint of the previous current slide to hide its
753 // current slide indicator.
754 mpPresenterController->GetPaintManager()->Invalidate(
755 mxWindow,
756 maCurrentSlideFrameBoundingBox);
757
758 // Request a repaint of the new current slide to show its
759 // current slide indicator.
760 maCurrentSlideFrameBoundingBox = mpCurrentSlideFrameRenderer->GetBoundingBox(
761 mpLayout->GetBoundingBox(mnCurrentSlideIndex));
762 mpPresenterController->GetPaintManager()->Invalidate(
763 mxWindow,
764 maCurrentSlideFrameBoundingBox);
765 }
766 }
767 }
768
769
770
771
getCurrentPage(void)772 Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage (void)
773 throw (RuntimeException)
774 {
775 ThrowIfDisposed();
776 return NULL;
777 }
778
779
780
781
782 //-----------------------------------------------------------------------------
783
UpdateLayout(void)784 void PresenterSlideSorter::UpdateLayout (void)
785 {
786 if ( ! mxWindow.is())
787 return;
788
789 mbIsLayoutPending = false;
790 mbIsPaintPending = true;
791
792 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
793 awt::Rectangle aCenterBox (aWindowBox);
794 sal_Int32 nLeftBorderWidth (aWindowBox.X);
795
796 // Get border width.
797 PresenterPaneContainer::SharedPaneDescriptor pPane (
798 mpPresenterController->GetPaneContainer()->FindViewURL(
799 mxViewId->getResourceURL()));
800 do
801 {
802 if (pPane.get() == NULL)
803 break;
804 if ( ! pPane->mxPane.is())
805 break;
806
807 Reference<drawing::framework::XPaneBorderPainter> xBorderPainter (
808 pPane->mxPane->GetPaneBorderPainter());
809 if ( ! xBorderPainter.is())
810 break;
811 aCenterBox = xBorderPainter->addBorder (
812 mxViewId->getAnchor()->getResourceURL(),
813 awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height),
814 drawing::framework::BorderType_INNER_BORDER);
815 }
816 while(false);
817
818 // Place vertical separator.
819 mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
820
821 PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth);
822
823 geometry::RealRectangle2D aUpperBox(
824 gnHorizontalBorder,
825 gnVerticalBorder,
826 aWindowBox.Width - 2*gnHorizontalBorder,
827 mnSeparatorY - gnVerticalGap);
828
829 // Determine whether the scroll bar has to be displayed.
830 aUpperBox = PlaceScrollBars(aUpperBox);
831
832 mpLayout->Update(aUpperBox, GetSlideAspectRatio());
833 mpLayout->SetupVisibleArea();
834 mpLayout->UpdateScrollBars();
835
836 // Tell the preview cache about some of the values.
837 mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize);
838 mxPreviewCache->setVisibleRange(
839 mpLayout->GetFirstVisibleSlideIndex(),
840 mpLayout->GetLastVisibleSlideIndex());
841
842 // Clear the frame polygon so that it is re-created on the next paint.
843 mxPreviewFrame = NULL;
844 }
845
846
847
848
PlaceScrollBars(const geometry::RealRectangle2D & rUpperBox)849 geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars (
850 const geometry::RealRectangle2D& rUpperBox)
851 {
852 mpLayout->Update(rUpperBox, GetSlideAspectRatio());
853 bool bIsScrollBarNeeded (false);
854 Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY_THROW);
855 if (xSlides.is())
856 bIsScrollBarNeeded = mpLayout->IsScrollBarNeeded(xSlides->getCount());
857
858 if (mpLayout->GetOrientation() == Layout::Vertical)
859 {
860 if (mpVerticalScrollBar.get() != NULL)
861 {
862 if (bIsScrollBarNeeded)
863 {
864 // Place vertical scroll bar at right border.
865 mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
866 rUpperBox.X2 - mpVerticalScrollBar->GetSize(),
867 rUpperBox.Y1,
868 rUpperBox.X2,
869 rUpperBox.Y2));
870 mpVerticalScrollBar->SetVisible(true);
871
872 // Reduce area covered by the scroll bar from the available
873 // space.
874 return geometry::RealRectangle2D(
875 rUpperBox.X1,
876 rUpperBox.Y1,
877 rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap,
878 rUpperBox.Y2);
879 }
880 else
881 mpVerticalScrollBar->SetVisible(false);
882 }
883 }
884 else
885 {
886 if (mpHorizontalScrollBar.get() != NULL)
887 {
888 if (bIsScrollBarNeeded)
889 {
890 // Place horixontal scroll bar at the bottom.
891 mpHorizontalScrollBar->SetPosSize(geometry::RealRectangle2D(
892 rUpperBox.X1,
893 rUpperBox.Y2 - mpHorizontalScrollBar->GetSize(),
894 rUpperBox.X2,
895 rUpperBox.Y2));
896 mpHorizontalScrollBar->SetVisible(true);
897
898 // Reduce area covered by the scroll bar from the available
899 // space.
900 return geometry::RealRectangle2D(
901 rUpperBox.X1,
902 rUpperBox.Y1,
903 rUpperBox.X2,
904 rUpperBox.Y2 - mpHorizontalScrollBar->GetSize() - gnVerticalGap);
905 }
906 else
907 mpHorizontalScrollBar->SetVisible(false);
908 }
909 }
910
911 return rUpperBox;
912 }
913
914
915
916
PlaceCloseButton(const PresenterPaneContainer::SharedPaneDescriptor & rpPane,const awt::Rectangle & rCenterBox,const sal_Int32 nLeftBorderWidth)917 void PresenterSlideSorter::PlaceCloseButton (
918 const PresenterPaneContainer::SharedPaneDescriptor& rpPane,
919 const awt::Rectangle& rCenterBox,
920 const sal_Int32 nLeftBorderWidth)
921 {
922 // Place button. When the callout is near the center then the button is
923 // centered over the callout. Otherwise it is centered with respect to
924 // the whole window.
925 sal_Int32 nCloseButtonCenter (rCenterBox.Width/2);
926 if (rpPane.get() != NULL && rpPane->mxPane.is())
927 {
928 const sal_Int32 nCalloutCenter (rpPane->mxPane->GetCalloutAnchor().X - nLeftBorderWidth);
929 const sal_Int32 nDistanceFromWindowCenter (abs(nCalloutCenter - rCenterBox.Width/2));
930 const sal_Int32 nButtonWidth (mpCloseButton->GetSize().Width);
931 const static sal_Int32 nMaxDistanceForCalloutCentering (nButtonWidth * 2);
932 if (nDistanceFromWindowCenter < nMaxDistanceForCalloutCentering)
933 {
934 if (nCalloutCenter < nButtonWidth/2)
935 nCloseButtonCenter = nButtonWidth/2;
936 else if (nCalloutCenter > rCenterBox.Width-nButtonWidth/2)
937 nCloseButtonCenter = rCenterBox.Width-nButtonWidth/2;
938 else
939 nCloseButtonCenter = nCalloutCenter;
940 }
941 }
942 mpCloseButton->SetCenter(geometry::RealPoint2D(
943 nCloseButtonCenter,
944 rCenterBox.Height - mpCloseButton->GetSize().Height/ 2));
945 }
946
947
948
949
ClearBackground(const Reference<rendering::XCanvas> & rxCanvas,const awt::Rectangle & rUpdateBox)950 void PresenterSlideSorter::ClearBackground (
951 const Reference<rendering::XCanvas>& rxCanvas,
952 const awt::Rectangle& rUpdateBox)
953 {
954 OSL_ASSERT(rxCanvas.is());
955
956 const awt::Rectangle aWindowBox (mxWindow->getPosSize());
957 mpPresenterController->GetCanvasHelper()->Paint(
958 mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
959 rxCanvas,
960 rUpdateBox,
961 awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
962 awt::Rectangle());
963 }
964
965
966
967
GetSlideAspectRatio(void) const968 double PresenterSlideSorter::GetSlideAspectRatio (void) const
969 {
970 double nSlideAspectRatio (28.0/21.0);
971
972 try
973 {
974 Reference<container::XIndexAccess> xSlides(mxSlideShowController, UNO_QUERY_THROW);
975 if (mxSlideShowController.is() && xSlides->getCount()>0)
976 {
977 Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
978 sal_Int32 nWidth (28000);
979 sal_Int32 nHeight (21000);
980 if ((xProperties->getPropertyValue(OUString::createFromAscii("Width")) >>= nWidth)
981 && (xProperties->getPropertyValue(OUString::createFromAscii("Height")) >>= nHeight)
982 && nHeight > 0)
983 {
984 nSlideAspectRatio = double(nWidth) / double(nHeight);
985 }
986 }
987 }
988 catch (RuntimeException&)
989 {
990 OSL_ASSERT(false);
991 }
992
993 return nSlideAspectRatio;
994 }
995
996
997
998
GetPreview(const sal_Int32 nSlideIndex)999 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex)
1000 {
1001 if (nSlideIndex < 0 || nSlideIndex>=mpLayout->mnSlideCount)
1002 return NULL;
1003 else if (mxPane.is())
1004 return mxPreviewCache->getSlidePreview(nSlideIndex, mxPane->getCanvas());
1005 else
1006 return NULL;
1007 }
1008
1009
1010
1011
PaintPreview(const Reference<rendering::XCanvas> & rxCanvas,const css::awt::Rectangle & rUpdateBox,const sal_Int32 nSlideIndex)1012 void PresenterSlideSorter::PaintPreview (
1013 const Reference<rendering::XCanvas>& rxCanvas,
1014 const css::awt::Rectangle& rUpdateBox,
1015 const sal_Int32 nSlideIndex)
1016 {
1017 OSL_ASSERT(rxCanvas.is());
1018
1019 geometry::IntegerSize2D aSize (mpLayout->maPreviewSize);
1020
1021 if (PresenterGeometryHelper::AreRectanglesDisjoint(
1022 rUpdateBox,
1023 mpLayout->GetBoundingBox(nSlideIndex)))
1024 {
1025 return;
1026 }
1027
1028 Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex));
1029
1030 const geometry::RealPoint2D aTopLeft (
1031 mpLayout->GetWindowPosition(
1032 mpLayout->GetPoint(nSlideIndex, -1, -1)));
1033
1034 // Create clip rectangle as intersection of the current update area and
1035 // the bounding box of all previews.
1036 geometry::RealRectangle2D aBoundingBox (mpLayout->maBoundingBox);
1037 aBoundingBox.Y2 += 1;
1038 const geometry::RealRectangle2D aClipBox (
1039 PresenterGeometryHelper::Intersection(
1040 PresenterGeometryHelper::ConvertRectangle(rUpdateBox),
1041 aBoundingBox));
1042 Reference<rendering::XPolyPolygon2D> xClip (
1043 PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice()));
1044
1045 const rendering::ViewState aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip);
1046
1047
1048 rendering::RenderState aRenderState (
1049 geometry::AffineMatrix2D(
1050 1, 0, aTopLeft.X,
1051 0, 1, aTopLeft.Y),
1052 NULL,
1053 Sequence<double>(4),
1054 rendering::CompositeOperation::SOURCE);
1055
1056
1057 // Emphasize the current slide.
1058 if (nSlideIndex == mnCurrentSlideIndex)
1059 {
1060 if (mpCurrentSlideFrameRenderer.get() != NULL)
1061 {
1062 const awt::Rectangle aSlideBoundingBox(
1063 sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.X),
1064 sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.Y),
1065 aSize.Width,
1066 aSize.Height);
1067 maCurrentSlideFrameBoundingBox
1068 = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox);
1069 mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame (
1070 aSlideBoundingBox,
1071 mxCanvas,
1072 aClipBox);
1073 }
1074 }
1075
1076 // Paint the preview.
1077 if (xPreview.is())
1078 {
1079 aSize = xPreview->getSize();
1080 if (aSize.Width > 0 && aSize.Height > 0)
1081 {
1082 rxCanvas->drawBitmap(xPreview, aViewState, aRenderState);
1083 }
1084 }
1085
1086 // Create a polygon that is used to paint a frame around previews. Its
1087 // coordinates are chosen in the local coordinate system of a preview.
1088 if ( ! mxPreviewFrame.is())
1089 mxPreviewFrame = PresenterGeometryHelper::CreatePolygon(
1090 awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2),
1091 rxCanvas->getDevice());
1092
1093 // Paint a border around the preview.
1094 if (mxPreviewFrame.is())
1095 {
1096 const geometry::RealRectangle2D aBox (0, 0, aSize.Width, aSize.Height);
1097 const util::Color aFrameColor (0x00000000);
1098 PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor);
1099 rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState);
1100 }
1101
1102 // Paint mouse over effect.
1103 mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip);
1104 }
1105
1106
1107
1108
Paint(const awt::Rectangle & rUpdateBox)1109 void PresenterSlideSorter::Paint (const awt::Rectangle& rUpdateBox)
1110 {
1111 const bool bCanvasChanged ( ! mxCanvas.is());
1112 if ( ! ProvideCanvas())
1113 return;
1114
1115 if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
1116 {
1117 OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0);
1118 return;
1119 }
1120
1121 mbIsPaintPending = false;
1122
1123 ClearBackground(mxCanvas, rUpdateBox);
1124
1125 // Give the canvas to the controls.
1126 if (bCanvasChanged)
1127 {
1128 if (mpHorizontalScrollBar.is())
1129 mpHorizontalScrollBar->SetCanvas(mxCanvas);
1130 if (mpVerticalScrollBar.is())
1131 mpVerticalScrollBar->SetCanvas(mxCanvas);
1132 if (mpCloseButton.is())
1133 mpCloseButton->SetCanvas(mxCanvas, mxWindow);
1134 }
1135
1136 // Now that the controls have a canvas we can do the layouting.
1137 if (mbIsLayoutPending)
1138 UpdateLayout();
1139
1140 // Paint the horizontal separator.
1141 rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0),
1142 NULL, Sequence<double>(4), rendering::CompositeOperation::SOURCE);
1143 PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor);
1144 mxCanvas->drawLine(
1145 geometry::RealPoint2D(0, mnSeparatorY),
1146 geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY),
1147 rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL),
1148 aRenderState);
1149
1150 // Paint the slides.
1151 if ( ! PresenterGeometryHelper::AreRectanglesDisjoint(
1152 rUpdateBox,
1153 PresenterGeometryHelper::ConvertRectangle(mpLayout->maBoundingBox)))
1154 {
1155 mpLayout->ForAllVisibleSlides(
1156 ::boost::bind(&PresenterSlideSorter::PaintPreview, this, mxCanvas, rUpdateBox, _1));
1157 }
1158
1159 Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
1160 if (xSpriteCanvas.is())
1161 xSpriteCanvas->updateScreen(sal_False);
1162 }
1163
1164
1165
1166
SetHorizontalOffset(const double nXOffset)1167 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset)
1168 {
1169 if (mpLayout->SetHorizontalOffset(nXOffset))
1170 {
1171 mxPreviewCache->setVisibleRange(
1172 mpLayout->GetFirstVisibleSlideIndex(),
1173 mpLayout->GetLastVisibleSlideIndex());
1174
1175 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1176 }
1177 }
1178
1179
1180
1181
SetVerticalOffset(const double nYOffset)1182 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset)
1183 {
1184 if (mpLayout->SetVerticalOffset(nYOffset))
1185 {
1186 mxPreviewCache->setVisibleRange(
1187 mpLayout->GetFirstVisibleSlideIndex(),
1188 mpLayout->GetLastVisibleSlideIndex());
1189
1190 mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1191 }
1192 }
1193
1194
1195
1196
GotoSlide(const sal_Int32 nSlideIndex)1197 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex)
1198 {
1199 mxSlideShowController->gotoSlideIndex(nSlideIndex);
1200 mpPresenterController->HideSlideSorter();
1201 }
1202
1203
1204
1205
ProvideCanvas(void)1206 bool PresenterSlideSorter::ProvideCanvas (void)
1207 {
1208 if ( ! mxCanvas.is())
1209 {
1210 if (mxPane.is())
1211 mxCanvas = mxPane->getCanvas();
1212
1213 // Register as event listener so that we are informed when the
1214 // canvas is disposed (and we have to fetch another one).
1215 Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
1216 if (xComponent.is())
1217 xComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
1218
1219 // Tell the scrollbar about the canvas.
1220 if (mpHorizontalScrollBar.is())
1221 mpHorizontalScrollBar->SetCanvas(mxCanvas);
1222
1223 mpCurrentSlideFrameRenderer.reset(
1224 new CurrentSlideFrameRenderer(mxComponentContext, mxCanvas));
1225 }
1226 return mxCanvas.is();
1227 }
1228
1229
1230
1231
ThrowIfDisposed(void)1232 void PresenterSlideSorter::ThrowIfDisposed (void)
1233 throw (lang::DisposedException)
1234 {
1235 if (rBHelper.bDisposed || rBHelper.bInDispose)
1236 {
1237 throw lang::DisposedException (
1238 OUString(RTL_CONSTASCII_USTRINGPARAM(
1239 "PresenterSlideSorter has been already disposed")),
1240 const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1241 }
1242 }
1243
1244
1245
1246
1247 //===== PresenterSlideSorter::Layout ==========================================
1248
Layout(const Orientation eOrientation,const::rtl::Reference<PresenterScrollBar> & rpHorizontalScrollBar,const::rtl::Reference<PresenterScrollBar> & rpVerticalScrollBar)1249 PresenterSlideSorter::Layout::Layout (
1250 const Orientation eOrientation,
1251 const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar,
1252 const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar)
1253 : maBoundingBox(),
1254 maPreviewSize(),
1255 mnHorizontalOffset(0),
1256 mnVerticalOffset(0),
1257 mnHorizontalGap(0),
1258 mnVerticalGap(0),
1259 mnHorizontalBorder(0),
1260 mnVerticalBorder(0),
1261 mnRowCount(1),
1262 mnColumnCount(1),
1263 mnSlideCount(0),
1264 mnSlideIndexAtMouse(-1),
1265 mnFirstVisibleColumn(-1),
1266 mnLastVisibleColumn(-1),
1267 mnFirstVisibleRow(-1),
1268 mnLastVisibleRow(-1),
1269 meOrientation(eOrientation),
1270 mpHorizontalScrollBar(rpHorizontalScrollBar),
1271 mpVerticalScrollBar(rpVerticalScrollBar)
1272 {
1273 }
1274
1275
1276
1277
Update(const geometry::RealRectangle2D & rBoundingBox,const double nSlideAspectRatio)1278 void PresenterSlideSorter::Layout::Update (
1279 const geometry::RealRectangle2D& rBoundingBox,
1280 const double nSlideAspectRatio)
1281 {
1282 maBoundingBox = rBoundingBox;
1283
1284 mnHorizontalBorder = gnHorizontalBorder;
1285 mnVerticalBorder = gnVerticalBorder;
1286
1287 const double nWidth (rBoundingBox.X2 - rBoundingBox.X1 - 2*mnHorizontalBorder);
1288 const double nHeight (rBoundingBox.Y2 - rBoundingBox.Y1 - 2*mnVerticalBorder);
1289 if (nWidth<=0 || nHeight<=0)
1290 return;
1291
1292 double nPreviewWidth;
1293
1294 // Determine column count, preview width, and horizontal gap (borders
1295 // are half the gap). Try to use the preferred values. Try more to
1296 // stay in the valid intervalls. This last constraint may be not
1297 // fullfilled in some cases.
1298 const double nElementWidth = nWidth / gnPreferredColumnCount;
1299 if (nElementWidth < gnMinimalPreviewWidth + gnMinimalHorizontalPreviewGap)
1300 {
1301 // The preferred column count is too large.
1302 // Can we use the preferred preview width?
1303 if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1304 {
1305 // Yes.
1306 nPreviewWidth = gnPreferredPreviewWidth;
1307 mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1308 / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1309 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1310 }
1311 else
1312 {
1313 // No. Set the column count to 1 and adapt preview width and
1314 // gap.
1315 mnColumnCount = 1;
1316 mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1317 if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1318 nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap;
1319 else
1320 nPreviewWidth = ::std::max(gnMinimalPreviewWidth, nWidth-mnHorizontalGap);
1321 }
1322 }
1323 else if (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap)
1324 {
1325 // The preferred column count is too small.
1326 nPreviewWidth = gnPreferredPreviewWidth;
1327 mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1328 / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1329 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1330 }
1331 else
1332 {
1333 // The preferred column count is possible. Determine gap and
1334 // preview width.
1335 mnColumnCount = gnPreferredColumnCount;
1336 if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap)
1337 {
1338 // Use the minimal gap and adapt the preview width.
1339 mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1340 nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1341 }
1342 else if (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap)
1343 {
1344 // Use the maximal gap and adapt the preview width.
1345 mnHorizontalGap = round(gnMaximalHorizontalPreviewGap);
1346 nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1347 }
1348 else
1349 {
1350 // Use the preferred preview width and adapt the gap.
1351 nPreviewWidth = gnPreferredPreviewWidth;
1352 mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1353 }
1354 }
1355
1356 // Now determine the row count, preview height, and vertical gap.
1357 const double nPreviewHeight = nPreviewWidth / nSlideAspectRatio;
1358 mnRowCount = ::std::max(
1359 sal_Int32(1),
1360 sal_Int32(ceil((nHeight+gnPreferredVerticalPreviewGap)
1361 / (nPreviewHeight + gnPreferredVerticalPreviewGap))));
1362 mnVerticalGap = round(gnPreferredVerticalPreviewGap);
1363
1364 maPreviewSize = geometry::IntegerSize2D(floor(nPreviewWidth), floor(nPreviewHeight));
1365
1366 // Reset the offset.
1367 if (meOrientation == Horizontal)
1368 {
1369 mnVerticalOffset = round(-(nHeight
1370 - mnRowCount*maPreviewSize.Height - (mnRowCount-1)*mnVerticalGap)
1371 / 2);
1372 mnHorizontalOffset = 0;
1373 }
1374 else
1375 {
1376 mnVerticalOffset = 0;
1377 mnHorizontalOffset = round(-(nWidth
1378 - mnColumnCount*maPreviewSize.Width
1379 - (mnColumnCount-1)*mnHorizontalGap)
1380 / 2);
1381 }
1382 }
1383
1384
1385
1386
SetupVisibleArea(void)1387 void PresenterSlideSorter::Layout::SetupVisibleArea (void)
1388 {
1389 geometry::RealPoint2D aPoint (GetLocalPosition(
1390 geometry::RealPoint2D(maBoundingBox.X1, maBoundingBox.Y1)));
1391 if (meOrientation == Horizontal)
1392 {
1393 mnFirstVisibleColumn = ::std::max(sal_Int32(0), GetColumn(aPoint));
1394 mnFirstVisibleRow = 0;
1395 }
1396 else
1397 {
1398 mnFirstVisibleColumn = 0;
1399 mnFirstVisibleRow = ::std::max(sal_Int32(0), GetRow(aPoint));
1400 }
1401
1402 aPoint = GetLocalPosition(geometry::RealPoint2D( maBoundingBox.X2, maBoundingBox.Y2));
1403 if (meOrientation == Horizontal)
1404 {
1405 mnLastVisibleColumn = GetColumn(aPoint, true);
1406 mnLastVisibleRow = mnRowCount - 1;
1407 }
1408 else
1409 {
1410 mnLastVisibleColumn = mnColumnCount - 1;
1411 mnLastVisibleRow = GetRow(aPoint, true);
1412 }
1413 }
1414
1415
1416
1417
IsScrollBarNeeded(const sal_Int32 nSlideCount)1418 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount)
1419 {
1420 geometry::RealPoint2D aBottomRight;
1421 if (GetOrientation() == Layout::Vertical)
1422 aBottomRight = GetPoint(
1423 mnColumnCount * (GetRow(nSlideCount)+1) - 1, +1, +1);
1424 else
1425 aBottomRight = GetPoint(
1426 mnRowCount * (GetColumn(nSlideCount)+1) - 1, +1, +1);
1427 return aBottomRight.X > maBoundingBox.X2-maBoundingBox.X1
1428 || aBottomRight.Y > maBoundingBox.Y2-maBoundingBox.Y1;
1429 }
1430
1431
1432
1433
GetLocalPosition(const geometry::RealPoint2D & rWindowPoint) const1434 geometry::RealPoint2D PresenterSlideSorter::Layout::GetLocalPosition(
1435 const geometry::RealPoint2D& rWindowPoint) const
1436 {
1437 return css::geometry::RealPoint2D(
1438 rWindowPoint.X - maBoundingBox.X1 + mnHorizontalOffset,
1439 rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset);
1440 }
1441
1442
1443
1444
GetWindowPosition(const geometry::RealPoint2D & rLocalPoint) const1445 geometry::RealPoint2D PresenterSlideSorter::Layout::GetWindowPosition(
1446 const geometry::RealPoint2D& rLocalPoint) const
1447 {
1448 return css::geometry::RealPoint2D(
1449 rLocalPoint.X - mnHorizontalOffset + maBoundingBox.X1,
1450 rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1);
1451 }
1452
1453
1454
1455
GetColumn(const css::geometry::RealPoint2D & rLocalPoint,const bool bReturnInvalidValue) const1456 sal_Int32 PresenterSlideSorter::Layout::GetColumn (
1457 const css::geometry::RealPoint2D& rLocalPoint,
1458 const bool bReturnInvalidValue) const
1459 {
1460 const sal_Int32 nColumn(floor(
1461 (rLocalPoint.X + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap)));
1462 if (bReturnInvalidValue
1463 || (nColumn>=mnFirstVisibleColumn && nColumn<=mnLastVisibleColumn))
1464 {
1465 return nColumn;
1466 }
1467 else
1468 return -1;
1469 }
1470
1471
1472
1473
GetRow(const css::geometry::RealPoint2D & rLocalPoint,const bool bReturnInvalidValue) const1474 sal_Int32 PresenterSlideSorter::Layout::GetRow (
1475 const css::geometry::RealPoint2D& rLocalPoint,
1476 const bool bReturnInvalidValue) const
1477 {
1478 const sal_Int32 nRow (floor(
1479 (rLocalPoint.Y + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap)));
1480 if (bReturnInvalidValue
1481 || (nRow>=mnFirstVisibleRow && nRow<=mnLastVisibleRow))
1482 {
1483 return nRow;
1484 }
1485 else
1486 return -1;
1487 }
1488
1489
1490
1491
GetSlideIndexForPosition(const css::geometry::RealPoint2D & rWindowPoint) const1492 sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition (
1493 const css::geometry::RealPoint2D& rWindowPoint) const
1494 {
1495 if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint))
1496 return -1;
1497
1498 const css::geometry::RealPoint2D aLocalPosition (GetLocalPosition(rWindowPoint));
1499 const sal_Int32 nColumn (GetColumn(aLocalPosition));
1500 const sal_Int32 nRow (GetRow(aLocalPosition));
1501
1502 if (nColumn < 0 || nRow < 0)
1503 return -1;
1504 else
1505 {
1506 sal_Int32 nIndex (GetIndex(nRow, nColumn));
1507 if (nIndex >= mnSlideCount)
1508 return -1;
1509 else
1510 return nIndex;
1511 }
1512 }
1513
1514
1515
1516
GetPoint(const sal_Int32 nSlideIndex,const sal_Int32 nRelativeHorizontalPosition,const sal_Int32 nRelativeVerticalPosition) const1517 geometry::RealPoint2D PresenterSlideSorter::Layout::GetPoint (
1518 const sal_Int32 nSlideIndex,
1519 const sal_Int32 nRelativeHorizontalPosition,
1520 const sal_Int32 nRelativeVerticalPosition) const
1521 {
1522 sal_Int32 nColumn (GetColumn(nSlideIndex));
1523 sal_Int32 nRow (GetRow(nSlideIndex));
1524
1525 geometry::RealPoint2D aPosition (
1526 mnHorizontalBorder + nColumn*(maPreviewSize.Width+mnHorizontalGap),
1527 mnVerticalBorder + nRow*(maPreviewSize.Height+mnVerticalGap));
1528
1529 if (nRelativeHorizontalPosition >= 0)
1530 {
1531 if (nRelativeHorizontalPosition > 0)
1532 aPosition.X += maPreviewSize.Width;
1533 else
1534 aPosition.X += maPreviewSize.Width / 2.0;
1535 }
1536 if (nRelativeVerticalPosition >= 0)
1537 {
1538 if (nRelativeVerticalPosition > 0)
1539 aPosition.Y += maPreviewSize.Height;
1540 else
1541 aPosition.Y += maPreviewSize.Height / 2.0;
1542 }
1543
1544 return aPosition;
1545 }
1546
1547
1548
1549
GetBoundingBox(const sal_Int32 nSlideIndex) const1550 awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) const
1551 {
1552 const geometry::RealPoint2D aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex, -1, -1)));
1553 return PresenterGeometryHelper::ConvertRectangle(
1554 geometry::RealRectangle2D(
1555 aWindowPosition.X,
1556 aWindowPosition.Y,
1557 aWindowPosition.X + maPreviewSize.Width,
1558 aWindowPosition.Y + maPreviewSize.Height));
1559 }
1560
1561
1562
1563
ForAllVisibleSlides(const::boost::function<void (sal_Int32)> & rAction)1564 void PresenterSlideSorter::Layout::ForAllVisibleSlides (const ::boost::function<void(sal_Int32)>& rAction)
1565 {
1566 for (sal_Int32 nRow=mnFirstVisibleRow; nRow<=mnLastVisibleRow; ++nRow)
1567 {
1568 for (sal_Int32 nColumn=mnFirstVisibleColumn; nColumn<=mnLastVisibleColumn; ++nColumn)
1569 {
1570 const sal_Int32 nSlideIndex (GetIndex(nRow, nColumn));
1571 if (nSlideIndex >= mnSlideCount)
1572 return;
1573 rAction(nSlideIndex);
1574 }
1575 }
1576 }
1577
1578
1579
1580
GetFirstVisibleSlideIndex(void) const1581 sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex (void) const
1582 {
1583 return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn);
1584 }
1585
1586
1587
1588
GetLastVisibleSlideIndex(void) const1589 sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex (void) const
1590 {
1591 return ::std::min(
1592 GetIndex(mnLastVisibleRow, mnLastVisibleColumn),
1593 mnSlideCount);
1594 }
1595
1596
1597
1598
SetHorizontalOffset(const double nOffset)1599 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset)
1600 {
1601 if (mnHorizontalOffset != nOffset)
1602 {
1603 mnHorizontalOffset = round(nOffset);
1604 SetupVisibleArea();
1605 UpdateScrollBars();
1606 return true;
1607 }
1608 else
1609 return false;
1610 }
1611
1612
1613
1614
SetVerticalOffset(const double nOffset)1615 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset)
1616 {
1617 if (mnVerticalOffset != nOffset)
1618 {
1619 mnVerticalOffset = round(nOffset);
1620 SetupVisibleArea();
1621 UpdateScrollBars();
1622 return true;
1623 }
1624 else
1625 return false;
1626 }
1627
1628
1629
1630
1631 PresenterSlideSorter::Layout::Orientation
GetOrientation(void) const1632 PresenterSlideSorter::Layout::GetOrientation (void) const
1633 {
1634 return meOrientation;
1635 }
1636
1637
1638
1639
UpdateScrollBars(void)1640 void PresenterSlideSorter::Layout::UpdateScrollBars (void)
1641 {
1642 sal_Int32 nTotalColumnCount (0);
1643 sal_Int32 nTotalRowCount (0);
1644 if (meOrientation == Horizontal)
1645 {
1646 nTotalColumnCount = sal_Int32(ceil(double(mnSlideCount) / double(mnRowCount)));
1647 nTotalRowCount = mnRowCount;
1648 }
1649 else
1650 {
1651 nTotalColumnCount = mnColumnCount;
1652 nTotalRowCount = sal_Int32(ceil(double(mnSlideCount) / double(mnColumnCount)));
1653 }
1654
1655 if (mpHorizontalScrollBar.get() != NULL)
1656 {
1657 mpHorizontalScrollBar->SetTotalSize(
1658 nTotalColumnCount * maPreviewSize.Width
1659 + (nTotalColumnCount-1) * mnHorizontalGap
1660 + 2*mnHorizontalBorder);
1661 mpHorizontalScrollBar->SetThumbPosition(mnHorizontalOffset, false);
1662 mpHorizontalScrollBar->SetThumbSize(maBoundingBox.X2 - maBoundingBox.X1 + 1);
1663 mpHorizontalScrollBar->SetLineHeight(maPreviewSize.Width);
1664 }
1665 if (mpVerticalScrollBar.get() != NULL)
1666 {
1667 mpVerticalScrollBar->SetTotalSize(
1668 nTotalRowCount * maPreviewSize.Height
1669 + (nTotalRowCount-1) * mnVerticalGap
1670 + 2*mnVerticalGap);
1671 mpVerticalScrollBar->SetThumbPosition(mnVerticalOffset, false);
1672 mpVerticalScrollBar->SetThumbSize(maBoundingBox.Y2 - maBoundingBox.Y1 + 1);
1673 mpVerticalScrollBar->SetLineHeight(maPreviewSize.Height);
1674 }
1675
1676
1677
1678 // No place yet for the vertical scroll bar.
1679 }
1680
1681
1682
1683
GetIndex(const sal_Int32 nRow,const sal_Int32 nColumn) const1684 sal_Int32 PresenterSlideSorter::Layout::GetIndex (
1685 const sal_Int32 nRow,
1686 const sal_Int32 nColumn) const
1687 {
1688 if (meOrientation == Horizontal)
1689 return nColumn * mnRowCount + nRow;
1690 else
1691 return nRow * mnColumnCount + nColumn;
1692 }
1693
1694
1695
1696
GetRow(const sal_Int32 nSlideIndex) const1697 sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) const
1698 {
1699 if (meOrientation == Horizontal)
1700 return nSlideIndex % mnRowCount;
1701 else
1702 return nSlideIndex / mnColumnCount;
1703 }
1704
1705
1706
1707
GetColumn(const sal_Int32 nSlideIndex) const1708 sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) const
1709 {
1710 if (meOrientation == Horizontal)
1711 return nSlideIndex / mnRowCount;
1712 else
1713 return nSlideIndex % mnColumnCount;
1714 }
1715
1716
1717
1718
1719 //===== PresenterSlideSorter::MouseOverManager ================================
1720
MouseOverManager(const Reference<container::XIndexAccess> & rxSlides,const::boost::shared_ptr<PresenterTheme> & rpTheme,const Reference<awt::XWindow> & rxInvalidateTarget,const::boost::shared_ptr<PresenterPaintManager> & rpPaintManager)1721 PresenterSlideSorter::MouseOverManager::MouseOverManager (
1722 const Reference<container::XIndexAccess>& rxSlides,
1723 const ::boost::shared_ptr<PresenterTheme>& rpTheme,
1724 const Reference<awt::XWindow>& rxInvalidateTarget,
1725 const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager)
1726 : mxCanvas(),
1727 mxSlides(rxSlides),
1728 mpLeftLabelBitmap(),
1729 mpCenterLabelBitmap(),
1730 mpRightLabelBitmap(),
1731 mpFont(),
1732 mnSlideIndex(-1),
1733 maSlideBoundingBox(),
1734 mxInvalidateTarget(rxInvalidateTarget),
1735 mpPaintManager(rpPaintManager)
1736 {
1737 if (rpTheme.get()!=NULL)
1738 {
1739 ::boost::shared_ptr<PresenterBitmapContainer> pBitmaps (rpTheme->GetBitmapContainer());
1740 if (pBitmaps.get() != NULL)
1741 {
1742 mpLeftLabelBitmap = pBitmaps->GetBitmap(A2S("LabelLeft"));
1743 mpCenterLabelBitmap = pBitmaps->GetBitmap(A2S("LabelCenter"));
1744 mpRightLabelBitmap = pBitmaps->GetBitmap(A2S("LabelRight"));
1745 }
1746
1747 mpFont = rpTheme->GetFont(A2S("SlideSorterLabelFont"));
1748 }
1749 }
1750
1751
1752
1753
~MouseOverManager(void)1754 PresenterSlideSorter::MouseOverManager::~MouseOverManager (void)
1755 {
1756 }
1757
1758
1759
1760
Paint(const sal_Int32 nSlideIndex,const Reference<rendering::XCanvas> & rxCanvas,const Reference<rendering::XPolyPolygon2D> & rxClip)1761 void PresenterSlideSorter::MouseOverManager::Paint (
1762 const sal_Int32 nSlideIndex,
1763 const Reference<rendering::XCanvas>& rxCanvas,
1764 const Reference<rendering::XPolyPolygon2D>& rxClip)
1765 {
1766 if (nSlideIndex != mnSlideIndex)
1767 return;
1768
1769 if (mxCanvas != rxCanvas)
1770 SetCanvas(rxCanvas);
1771 if (rxCanvas != NULL)
1772 {
1773 if ( ! mxBitmap.is())
1774 mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width);
1775 if (mxBitmap.is())
1776 {
1777 geometry::IntegerSize2D aSize (mxBitmap->getSize());
1778 const double nXOffset (maSlideBoundingBox.X
1779 + (maSlideBoundingBox.Width - aSize.Width) / 2.0);
1780 const double nYOffset (maSlideBoundingBox.Y
1781 + (maSlideBoundingBox.Height - aSize.Height) / 2.0);
1782 rxCanvas->drawBitmap(
1783 mxBitmap,
1784 rendering::ViewState(
1785 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1786 rxClip),
1787 rendering::RenderState(
1788 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1789 NULL,
1790 Sequence<double>(4),
1791 rendering::CompositeOperation::SOURCE));
1792 }
1793 }
1794 }
1795
1796
1797
1798
SetCanvas(const Reference<rendering::XCanvas> & rxCanvas)1799 void PresenterSlideSorter::MouseOverManager::SetCanvas (
1800 const Reference<rendering::XCanvas>& rxCanvas)
1801 {
1802 mxCanvas = rxCanvas;
1803 if (mpFont.get() != NULL)
1804 mpFont->PrepareFont(Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY));
1805 }
1806
1807
1808
1809
SetSlide(const sal_Int32 nSlideIndex,const awt::Rectangle & rBox)1810 void PresenterSlideSorter::MouseOverManager::SetSlide (
1811 const sal_Int32 nSlideIndex,
1812 const awt::Rectangle& rBox)
1813 {
1814 if (mnSlideIndex == nSlideIndex)
1815 return;
1816
1817 mnSlideIndex = -1;
1818 Invalidate();
1819
1820 maSlideBoundingBox = rBox;
1821 mnSlideIndex = nSlideIndex;
1822
1823 if (nSlideIndex >= 0)
1824 {
1825 if (mxSlides.get() != NULL)
1826 {
1827 msText = OUString();
1828
1829 Reference<beans::XPropertySet> xSlideProperties(mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
1830 if (xSlideProperties.is())
1831 xSlideProperties->getPropertyValue(A2S("LinkDisplayName")) >>= msText;
1832
1833 if (msText.getLength() == 0)
1834 msText = A2S("Slide ") + OUString::valueOf(nSlideIndex + 1);
1835 }
1836 }
1837 else
1838 {
1839 msText = OUString();
1840 }
1841 mxBitmap = NULL;
1842
1843 Invalidate();
1844 }
1845
1846
1847
1848
CreateBitmap(const OUString & rsText,const sal_Int32 nMaximalWidth) const1849 Reference<rendering::XBitmap> PresenterSlideSorter::MouseOverManager::CreateBitmap (
1850 const OUString& rsText,
1851 const sal_Int32 nMaximalWidth) const
1852 {
1853 if ( ! mxCanvas.is())
1854 return NULL;
1855
1856 if (mpFont.get()==NULL || !mpFont->mxFont.is())
1857 return NULL;
1858
1859 // Long text has to be shortened.
1860 const OUString sText (GetFittingText(rsText, nMaximalWidth
1861 - 2*gnHorizontalLabelBorder
1862 - 2*gnHorizontalLabelPadding));
1863
1864 // Determine the size of the label. Its height is defined by the
1865 // bitmaps that are used to paints its background. The width is defined
1866 // by the text.
1867 geometry::IntegerSize2D aLabelSize (CalculateLabelSize(sText));
1868
1869 // Create a new bitmap that will contain the complete label.
1870 Reference<rendering::XBitmap> xBitmap (
1871 mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize));
1872
1873 if ( ! xBitmap.is())
1874 return NULL;
1875
1876 Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY);
1877 if ( ! xBitmapCanvas.is())
1878 return NULL;
1879
1880 // Paint the background.
1881 PaintButtonBackground(xBitmapCanvas, aLabelSize);
1882
1883 // Paint the text.
1884 if (sText.getLength() > 0)
1885 {
1886
1887 const rendering::StringContext aContext (sText, 0, sText.getLength());
1888 const Reference<rendering::XTextLayout> xLayout (mpFont->mxFont->createTextLayout(
1889 aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
1890 const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
1891
1892 const double nXOffset = (aLabelSize.Width - aTextBBox.X2 + aTextBBox.X1) / 2;
1893 const double nYOffset = aLabelSize.Height
1894 - (aLabelSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y2;
1895
1896 const rendering::ViewState aViewState(
1897 geometry::AffineMatrix2D(1,0,0, 0,1,0),
1898 NULL);
1899
1900 rendering::RenderState aRenderState (
1901 geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1902 NULL,
1903 Sequence<double>(4),
1904 rendering::CompositeOperation::SOURCE);
1905 PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1906
1907 xBitmapCanvas->drawText(
1908 aContext,
1909 mpFont->mxFont,
1910 aViewState,
1911 aRenderState,
1912 rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1913 }
1914
1915 return xBitmap;
1916 }
1917
1918
1919
1920
GetFittingText(const OUString & rsText,const double nMaximalWidth) const1921 OUString PresenterSlideSorter::MouseOverManager::GetFittingText (
1922 const OUString& rsText,
1923 const double nMaximalWidth) const
1924 {
1925 const double nTextWidth (
1926 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width);
1927 if (nTextWidth > nMaximalWidth)
1928 {
1929 // Text is too wide. Shorten it by removing characters from the end
1930 // and replacing them by ellipses.
1931
1932 // Guess a start value of the final string length.
1933 double nBestWidth (0);
1934 OUString sBestCandidate;
1935 sal_Int32 nLength (round(rsText.getLength() * nMaximalWidth / nTextWidth));
1936 const OUString sEllipses (A2S("..."));
1937 while (true)
1938 {
1939 const OUString sCandidate (rsText.copy(0,nLength) + sEllipses);
1940 const double nWidth (
1941 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width);
1942 if (nWidth > nMaximalWidth)
1943 {
1944 // Candidate still too wide, shorten it.
1945 nLength -= 1;
1946 if (nLength <= 0)
1947 break;
1948 }
1949 else if (nWidth < nMaximalWidth)
1950 {
1951 // Candidate short enough.
1952 if (nWidth > nBestWidth)
1953 {
1954 // Best length so far.
1955 sBestCandidate = sCandidate;
1956 nBestWidth = nWidth;
1957 nLength += 1;
1958 if (nLength >= rsText.getLength())
1959 break;
1960 }
1961 else
1962 break;
1963 }
1964 else
1965 {
1966 // Candidate is exactly as long as it may be. Use it
1967 // without looking any further.
1968 sBestCandidate = sCandidate;
1969 break;
1970 }
1971 }
1972 return sBestCandidate;
1973 }
1974 else
1975 return rsText;
1976 }
1977
1978
1979
1980
CalculateLabelSize(const OUString & rsText) const1981 geometry::IntegerSize2D PresenterSlideSorter::MouseOverManager::CalculateLabelSize (
1982 const OUString& rsText) const
1983 {
1984 // Height is specified by the label bitmaps.
1985 sal_Int32 nHeight (32);
1986 if (mpCenterLabelBitmap.get() != NULL)
1987 {
1988 Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap());
1989 if (xBitmap.is())
1990 nHeight = xBitmap->getSize().Height;
1991 }
1992
1993 // Width is specified by text width and maximal width.
1994 const geometry::RealSize2D aTextSize (
1995 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText));
1996
1997 const sal_Int32 nWidth (round(aTextSize.Width + 2*gnHorizontalLabelPadding));
1998
1999 return geometry::IntegerSize2D(nWidth, nHeight);
2000 }
2001
2002
2003
2004
PaintButtonBackground(const Reference<rendering::XBitmapCanvas> & rxCanvas,const geometry::IntegerSize2D & rSize) const2005 void PresenterSlideSorter::MouseOverManager::PaintButtonBackground (
2006 const Reference<rendering::XBitmapCanvas>& rxCanvas,
2007 const geometry::IntegerSize2D& rSize) const
2008 {
2009 // Get the bitmaps for painting the label background.
2010 Reference<rendering::XBitmap> xLeftLabelBitmap;
2011 if (mpLeftLabelBitmap.get() != NULL)
2012 xLeftLabelBitmap = mpLeftLabelBitmap->GetNormalBitmap();
2013
2014 Reference<rendering::XBitmap> xCenterLabelBitmap;
2015 if (mpCenterLabelBitmap.get() != NULL)
2016 xCenterLabelBitmap = mpCenterLabelBitmap->GetNormalBitmap();
2017
2018 Reference<rendering::XBitmap> xRightLabelBitmap;
2019 if (mpRightLabelBitmap.get() != NULL)
2020 xRightLabelBitmap = mpRightLabelBitmap->GetNormalBitmap();
2021
2022 PresenterUIPainter::PaintHorizontalBitmapComposite (
2023 Reference<rendering::XCanvas>(rxCanvas, UNO_QUERY),
2024 awt::Rectangle(0,0, rSize.Width,rSize.Height),
2025 awt::Rectangle(0,0, rSize.Width,rSize.Height),
2026 xLeftLabelBitmap,
2027 xCenterLabelBitmap,
2028 xRightLabelBitmap);
2029 }
2030
2031
2032
2033
Invalidate(void)2034 void PresenterSlideSorter::MouseOverManager::Invalidate (void)
2035 {
2036 if (mpPaintManager.get() != NULL)
2037 mpPaintManager->Invalidate(mxInvalidateTarget, maSlideBoundingBox, true);
2038 }
2039
2040
2041
2042
2043 //===== PresenterSlideSorter::CurrentSlideFrameRenderer =======================
2044
CurrentSlideFrameRenderer(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::rendering::XCanvas> & rxCanvas)2045 PresenterSlideSorter::CurrentSlideFrameRenderer::CurrentSlideFrameRenderer (
2046 const css::uno::Reference<css::uno::XComponentContext>& rxContext,
2047 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas)
2048 : mpTopLeft(),
2049 mpTop(),
2050 mpTopRight(),
2051 mpLeft(),
2052 mpRight(),
2053 mpBottomLeft(),
2054 mpBottom(),
2055 mpBottomRight(),
2056 mnTopFrameSize(0),
2057 mnLeftFrameSize(0),
2058 mnRightFrameSize(0),
2059 mnBottomFrameSize(0)
2060 {
2061 PresenterConfigurationAccess aConfiguration (
2062 rxContext,
2063 OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"),
2064 PresenterConfigurationAccess::READ_ONLY);
2065 Reference<container::XHierarchicalNameAccess> xBitmaps (
2066 aConfiguration.GetConfigurationNode(
2067 A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps")),
2068 UNO_QUERY);
2069 if ( ! xBitmaps.is())
2070 return;
2071
2072 PresenterBitmapContainer aContainer (
2073 A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
2074 ::boost::shared_ptr<PresenterBitmapContainer>(),
2075 rxContext,
2076 rxCanvas);
2077
2078 mpTopLeft = aContainer.GetBitmap(A2S("TopLeft"));
2079 mpTop = aContainer.GetBitmap(A2S("Top"));
2080 mpTopRight = aContainer.GetBitmap(A2S("TopRight"));
2081 mpLeft = aContainer.GetBitmap(A2S("Left"));
2082 mpRight = aContainer.GetBitmap(A2S("Right"));
2083 mpBottomLeft = aContainer.GetBitmap(A2S("BottomLeft"));
2084 mpBottom = aContainer.GetBitmap(A2S("Bottom"));
2085 mpBottomRight = aContainer.GetBitmap(A2S("BottomRight"));
2086
2087 // Determine size of frame.
2088 if (mpTop.get() != NULL)
2089 mnTopFrameSize = mpTop->mnHeight;
2090 if (mpLeft.get() != NULL)
2091 mnLeftFrameSize = mpLeft->mnWidth;
2092 if (mpRight.get() != NULL)
2093 mnRightFrameSize = mpRight->mnWidth;
2094 if (mpBottom.get() != NULL)
2095 mnBottomFrameSize = mpBottom->mnHeight;
2096
2097 if (mpTopLeft.get() != NULL)
2098 {
2099 mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight);
2100 mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth);
2101 }
2102 if (mpTopRight.get() != NULL)
2103 {
2104 mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight);
2105 mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth);
2106 }
2107 if (mpBottomLeft.get() != NULL)
2108 {
2109 mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth);
2110 mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight);
2111 }
2112 if (mpBottomRight.get() != NULL)
2113 {
2114 mnRightFrameSize = ::std::max(mnRightFrameSize, mpBottomRight->mnWidth);
2115 mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomRight->mnHeight);
2116 }
2117 }
2118
2119
2120
2121
~CurrentSlideFrameRenderer(void)2122 PresenterSlideSorter::CurrentSlideFrameRenderer::~CurrentSlideFrameRenderer (void)
2123 {
2124 }
2125
2126
2127
2128
PaintCurrentSlideFrame(const awt::Rectangle & rSlideBoundingBox,const Reference<rendering::XCanvas> & rxCanvas,const geometry::RealRectangle2D & rClipBox)2129 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintCurrentSlideFrame (
2130 const awt::Rectangle& rSlideBoundingBox,
2131 const Reference<rendering::XCanvas>& rxCanvas,
2132 const geometry::RealRectangle2D& rClipBox)
2133 {
2134 if ( ! rxCanvas.is())
2135 return;
2136
2137 const Reference<rendering::XPolyPolygon2D> xClip (
2138 PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice()));
2139
2140 if (mpTop.get() != NULL)
2141 {
2142 PaintBitmapTiled(
2143 mpTop->GetNormalBitmap(),
2144 rxCanvas,
2145 rClipBox,
2146 rSlideBoundingBox.X,
2147 rSlideBoundingBox.Y - mpTop->mnHeight,
2148 rSlideBoundingBox.Width,
2149 mpTop->mnHeight);
2150 }
2151 if (mpLeft.get() != NULL)
2152 {
2153 PaintBitmapTiled(
2154 mpLeft->GetNormalBitmap(),
2155 rxCanvas,
2156 rClipBox,
2157 rSlideBoundingBox.X - mpLeft->mnWidth,
2158 rSlideBoundingBox.Y,
2159 mpLeft->mnWidth,
2160 rSlideBoundingBox.Height);
2161 }
2162 if (mpRight.get() != NULL)
2163 {
2164 PaintBitmapTiled(
2165 mpRight->GetNormalBitmap(),
2166 rxCanvas,
2167 rClipBox,
2168 rSlideBoundingBox.X + rSlideBoundingBox.Width,
2169 rSlideBoundingBox.Y,
2170 mpRight->mnWidth,
2171 rSlideBoundingBox.Height);
2172 }
2173 if (mpBottom.get() != NULL)
2174 {
2175 PaintBitmapTiled(
2176 mpBottom->GetNormalBitmap(),
2177 rxCanvas,
2178 rClipBox,
2179 rSlideBoundingBox.X,
2180 rSlideBoundingBox.Y + rSlideBoundingBox.Height,
2181 rSlideBoundingBox.Width,
2182 mpBottom->mnHeight);
2183 }
2184 if (mpTopLeft.get() != NULL)
2185 {
2186 PaintBitmapOnce(
2187 mpTopLeft->GetNormalBitmap(),
2188 rxCanvas,
2189 xClip,
2190 rSlideBoundingBox.X - mpTopLeft->mnWidth,
2191 rSlideBoundingBox.Y - mpTopLeft->mnHeight);
2192 }
2193 if (mpTopRight.get() != NULL)
2194 {
2195 PaintBitmapOnce(
2196 mpTopRight->GetNormalBitmap(),
2197 rxCanvas,
2198 xClip,
2199 rSlideBoundingBox.X + rSlideBoundingBox.Width,
2200 rSlideBoundingBox.Y - mpTopLeft->mnHeight);
2201 }
2202 if (mpBottomLeft.get() != NULL)
2203 {
2204 PaintBitmapOnce(
2205 mpBottomLeft->GetNormalBitmap(),
2206 rxCanvas,
2207 xClip,
2208 rSlideBoundingBox.X - mpBottomLeft->mnWidth,
2209 rSlideBoundingBox.Y + rSlideBoundingBox.Height);
2210 }
2211 if (mpBottomRight.get() != NULL)
2212 {
2213 PaintBitmapOnce(
2214 mpBottomRight->GetNormalBitmap(),
2215 rxCanvas,
2216 xClip,
2217 rSlideBoundingBox.X + rSlideBoundingBox.Width,
2218 rSlideBoundingBox.Y + rSlideBoundingBox.Height);
2219 }
2220 }
2221
2222
2223
2224
GetBoundingBox(const awt::Rectangle & rSlideBoundingBox)2225 awt::Rectangle PresenterSlideSorter::CurrentSlideFrameRenderer::GetBoundingBox (
2226 const awt::Rectangle& rSlideBoundingBox)
2227 {
2228 return awt::Rectangle(
2229 rSlideBoundingBox.X - mnLeftFrameSize,
2230 rSlideBoundingBox.Y - mnTopFrameSize,
2231 rSlideBoundingBox.Width + mnLeftFrameSize + mnRightFrameSize,
2232 rSlideBoundingBox.Height + mnTopFrameSize + mnBottomFrameSize);
2233 }
2234
2235
2236
2237
PaintBitmapOnce(const css::uno::Reference<css::rendering::XBitmap> & rxBitmap,const css::uno::Reference<css::rendering::XCanvas> & rxCanvas,const Reference<rendering::XPolyPolygon2D> & rxClip,const double nX,const double nY)2238 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapOnce(
2239 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
2240 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
2241 const Reference<rendering::XPolyPolygon2D>& rxClip,
2242 const double nX,
2243 const double nY)
2244 {
2245 OSL_ASSERT(rxCanvas.is());
2246 if ( ! rxBitmap.is())
2247 return;
2248
2249 const rendering::ViewState aViewState(
2250 geometry::AffineMatrix2D(1,0,0, 0,1,0),
2251 rxClip);
2252
2253 const rendering::RenderState aRenderState (
2254 geometry::AffineMatrix2D(
2255 1, 0, nX,
2256 0, 1, nY),
2257 NULL,
2258 Sequence<double>(4),
2259 rendering::CompositeOperation::SOURCE);
2260
2261 rxCanvas->drawBitmap(
2262 rxBitmap,
2263 aViewState,
2264 aRenderState);
2265 }
2266
2267
2268
2269
PaintBitmapTiled(const css::uno::Reference<css::rendering::XBitmap> & rxBitmap,const css::uno::Reference<css::rendering::XCanvas> & rxCanvas,const geometry::RealRectangle2D & rClipBox,const double nX0,const double nY0,const double nWidth,const double nHeight)2270 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapTiled(
2271 const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
2272 const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
2273 const geometry::RealRectangle2D& rClipBox,
2274 const double nX0,
2275 const double nY0,
2276 const double nWidth,
2277 const double nHeight)
2278 {
2279 OSL_ASSERT(rxCanvas.is());
2280 if ( ! rxBitmap.is())
2281 return;
2282
2283 geometry::IntegerSize2D aSize (rxBitmap->getSize());
2284
2285 const rendering::ViewState aViewState(
2286 geometry::AffineMatrix2D(1,0,0, 0,1,0),
2287 PresenterGeometryHelper::CreatePolygon(
2288 PresenterGeometryHelper::Intersection(
2289 rClipBox,
2290 geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)),
2291 rxCanvas->getDevice()));
2292
2293 rendering::RenderState aRenderState (
2294 geometry::AffineMatrix2D(
2295 1, 0, nX0,
2296 0, 1, nY0),
2297 NULL,
2298 Sequence<double>(4),
2299 rendering::CompositeOperation::SOURCE);
2300
2301 const double nX1 = nX0 + nWidth;
2302 const double nY1 = nY0 + nHeight;
2303 for (double nY=nY0; nY<nY1; nY+=aSize.Height)
2304 for (double nX=nX0; nX<nX1; nX+=aSize.Width)
2305 {
2306 aRenderState.AffineTransform.m02 = nX;
2307 aRenderState.AffineTransform.m12 = nY;
2308 rxCanvas->drawBitmap(
2309 rxBitmap,
2310 aViewState,
2311 aRenderState);
2312 }
2313 }
2314
2315 } } // end of namespace ::sdext::presenter
2316