xref: /trunk/main/sdext/source/presenter/PresenterSlideSorter.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
495     if (rEventObject.Source == mxWindow)
496     {
497         mxWindow = NULL;
498         dispose();
499     }
500     else if (rEventObject.Source == mxPreviewCache)
501     {
502         mxPreviewCache = NULL;
503         dispose();
504     }
505     else if (rEventObject.Source == mxCanvas)
506     {
507         mxCanvas = NULL;
508         if (mpHorizontalScrollBar.is())
509             mpHorizontalScrollBar->SetCanvas(NULL);
510         mbIsLayoutPending = true;
511         mbIsPaintPending = true;
512 
513         mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
514     }
515 }
516 
517 
518 
519 
520 //----- XWindowListener -------------------------------------------------------
521 
windowResized(const awt::WindowEvent & rEvent)522 void SAL_CALL PresenterSlideSorter::windowResized (const awt::WindowEvent& rEvent)
523 {
524     (void)rEvent;
525     ThrowIfDisposed();
526     mbIsLayoutPending = true;
527     mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
528 }
529 
530 
531 
532 
windowMoved(const awt::WindowEvent & rEvent)533 void SAL_CALL PresenterSlideSorter::windowMoved (const awt::WindowEvent& rEvent)
534 {
535     (void)rEvent;
536     ThrowIfDisposed();
537 }
538 
539 
540 
541 
windowShown(const lang::EventObject & rEvent)542 void SAL_CALL PresenterSlideSorter::windowShown (const lang::EventObject& rEvent)
543 {
544     (void)rEvent;
545     ThrowIfDisposed();
546     mbIsLayoutPending = true;
547     mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
548 }
549 
550 
551 
552 
windowHidden(const lang::EventObject & rEvent)553 void SAL_CALL PresenterSlideSorter::windowHidden (const lang::EventObject& rEvent)
554 {
555     (void)rEvent;
556     ThrowIfDisposed();
557 }
558 
559 
560 
561 
562 //----- XPaintListener --------------------------------------------------------
563 
windowPaint(const css::awt::PaintEvent & rEvent)564 void SAL_CALL PresenterSlideSorter::windowPaint (const css::awt::PaintEvent& rEvent)
565 {
566     (void)rEvent;
567 
568     // Deactivated views must not be painted.
569     if ( ! mbIsPresenterViewActive)
570         return;
571 
572     Paint(rEvent.UpdateRect);
573 
574     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
575     if (xSpriteCanvas.is())
576         xSpriteCanvas->updateScreen(sal_False);
577 }
578 
579 
580 
581 
582 //----- XMouseListener --------------------------------------------------------
583 
mousePressed(const css::awt::MouseEvent & rEvent)584 void SAL_CALL PresenterSlideSorter::mousePressed (const css::awt::MouseEvent& rEvent)
585 {
586     const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y);
587     mnSlideIndexMousePressed = mpLayout->GetSlideIndexForPosition(aPosition);
588 }
589 
590 
591 
592 
mouseReleased(const css::awt::MouseEvent & rEvent)593 void SAL_CALL PresenterSlideSorter::mouseReleased (const css::awt::MouseEvent& rEvent)
594 {
595     const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y);
596     const sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
597 
598     if (nSlideIndex == mnSlideIndexMousePressed && mnSlideIndexMousePressed >= 0)
599     {
600         switch (rEvent.ClickCount)
601         {
602             case 1:
603             default:
604                 GotoSlide(nSlideIndex);
605                 break;
606 
607             case 2:
608                 OSL_ASSERT(mpPresenterController.get()!=NULL);
609                 OSL_ASSERT(mpPresenterController->GetWindowManager().get()!=NULL);
610                 mpPresenterController->GetWindowManager()->SetSlideSorterState(false);
611                 GotoSlide(nSlideIndex);
612                 break;
613         }
614     }
615 }
616 
617 
618 
619 
mouseEntered(const css::awt::MouseEvent & rEvent)620 void SAL_CALL PresenterSlideSorter::mouseEntered (const css::awt::MouseEvent& rEvent)
621 {
622     (void)rEvent;
623 }
624 
625 
626 
627 
mouseExited(const css::awt::MouseEvent & rEvent)628 void SAL_CALL PresenterSlideSorter::mouseExited (const css::awt::MouseEvent& rEvent)
629 {
630     (void)rEvent;
631     mnSlideIndexMousePressed = -1;
632     if (mpMouseOverManager.get() != NULL)
633         mpMouseOverManager->SetSlide(mnSlideIndexMousePressed, awt::Rectangle(0,0,0,0));
634 }
635 
636 
637 
638 
639 //----- XMouseMotionListener --------------------------------------------------
640 
mouseMoved(const css::awt::MouseEvent & rEvent)641 void SAL_CALL PresenterSlideSorter::mouseMoved (const css::awt::MouseEvent& rEvent)
642 {
643     if (mpMouseOverManager.get() != NULL)
644     {
645         const geometry::RealPoint2D aPosition (rEvent.X, rEvent.Y);
646         sal_Int32 nSlideIndex (mpLayout->GetSlideIndexForPosition(aPosition));
647 
648         if (nSlideIndex < 0)
649             mnSlideIndexMousePressed = -1;
650 
651         if (nSlideIndex < 0)
652         {
653             mpMouseOverManager->SetSlide(nSlideIndex, awt::Rectangle(0,0,0,0));
654         }
655         else
656         {
657             mpMouseOverManager->SetSlide(
658                 nSlideIndex,
659                 mpLayout->GetBoundingBox(nSlideIndex));
660         }
661     }
662 }
663 
664 
665 
666 
mouseDragged(const css::awt::MouseEvent & rEvent)667 void SAL_CALL PresenterSlideSorter::mouseDragged (const css::awt::MouseEvent& rEvent)
668 {
669     (void)rEvent;
670 }
671 
672 
673 
674 
675 //----- XResourceId -----------------------------------------------------------
676 
getResourceId(void)677 Reference<XResourceId> SAL_CALL PresenterSlideSorter::getResourceId (void)
678 {
679     ThrowIfDisposed();
680     return mxViewId;
681 }
682 
683 
684 
685 
isAnchorOnly(void)686 sal_Bool SAL_CALL PresenterSlideSorter::isAnchorOnly (void)
687 {
688     return false;
689 }
690 
691 
692 
693 
694 //----- XPropertyChangeListener -----------------------------------------------
695 
propertyChange(const css::beans::PropertyChangeEvent & rEvent)696 void SAL_CALL PresenterSlideSorter::propertyChange (
697     const css::beans::PropertyChangeEvent& rEvent)
698 {
699     (void)rEvent;
700 }
701 
702 
703 
704 
705 //----- XSlidePreviewCacheListener --------------------------------------------
706 
notifyPreviewCreation(sal_Int32 nSlideIndex)707 void SAL_CALL PresenterSlideSorter::notifyPreviewCreation (
708     sal_Int32 nSlideIndex)
709 {
710     OSL_ASSERT(mpLayout.get()!=NULL);
711 
712     awt::Rectangle aBBox (mpLayout->GetBoundingBox(nSlideIndex));
713     mpPresenterController->GetPaintManager()->Invalidate(mxWindow, aBBox, true);
714 }
715 
716 
717 
718 
719 //----- XDrawView -------------------------------------------------------------
720 
setCurrentPage(const Reference<drawing::XDrawPage> & rxSlide)721 void SAL_CALL PresenterSlideSorter::setCurrentPage (const Reference<drawing::XDrawPage>& rxSlide)
722 {
723     (void)rxSlide;
724 
725     ThrowIfDisposed();
726     ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex());
727 
728     if (mxSlideShowController.is())
729     {
730         const sal_Int32 nNewCurrentSlideIndex (mxSlideShowController->getCurrentSlideIndex());
731         if (nNewCurrentSlideIndex != mnCurrentSlideIndex)
732         {
733             mnCurrentSlideIndex = nNewCurrentSlideIndex;
734 
735             // Request a repaint of the previous current slide to hide its
736             // current slide indicator.
737             mpPresenterController->GetPaintManager()->Invalidate(
738                 mxWindow,
739                 maCurrentSlideFrameBoundingBox);
740 
741             // Request a repaint of the new current slide to show its
742             // current slide indicator.
743             maCurrentSlideFrameBoundingBox = mpCurrentSlideFrameRenderer->GetBoundingBox(
744                 mpLayout->GetBoundingBox(mnCurrentSlideIndex));
745             mpPresenterController->GetPaintManager()->Invalidate(
746                 mxWindow,
747                 maCurrentSlideFrameBoundingBox);
748         }
749     }
750 }
751 
752 
753 
754 
getCurrentPage(void)755 Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage (void)
756 {
757     ThrowIfDisposed();
758     return NULL;
759 }
760 
761 
762 
763 
764 //-----------------------------------------------------------------------------
765 
UpdateLayout(void)766 void PresenterSlideSorter::UpdateLayout (void)
767 {
768     if ( ! mxWindow.is())
769         return;
770 
771     mbIsLayoutPending = false;
772     mbIsPaintPending = true;
773 
774     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
775     awt::Rectangle aCenterBox (aWindowBox);
776     sal_Int32 nLeftBorderWidth (aWindowBox.X);
777 
778     // Get border width.
779     PresenterPaneContainer::SharedPaneDescriptor pPane (
780         mpPresenterController->GetPaneContainer()->FindViewURL(
781             mxViewId->getResourceURL()));
782     do
783     {
784         if (pPane.get() == NULL)
785             break;
786         if ( ! pPane->mxPane.is())
787             break;
788 
789         Reference<drawing::framework::XPaneBorderPainter> xBorderPainter (
790             pPane->mxPane->GetPaneBorderPainter());
791         if ( ! xBorderPainter.is())
792             break;
793         aCenterBox = xBorderPainter->addBorder (
794             mxViewId->getAnchor()->getResourceURL(),
795             awt::Rectangle(0, 0, aWindowBox.Width, aWindowBox.Height),
796             drawing::framework::BorderType_INNER_BORDER);
797     }
798     while(false);
799 
800     // Place vertical separator.
801     mnSeparatorY = aWindowBox.Height - mpCloseButton->GetSize().Height - gnVerticalButtonPadding;
802 
803     PlaceCloseButton(pPane, aWindowBox, nLeftBorderWidth);
804 
805     geometry::RealRectangle2D aUpperBox(
806         gnHorizontalBorder,
807         gnVerticalBorder,
808         aWindowBox.Width - 2*gnHorizontalBorder,
809         mnSeparatorY - gnVerticalGap);
810 
811     // Determine whether the scroll bar has to be displayed.
812     aUpperBox = PlaceScrollBars(aUpperBox);
813 
814     mpLayout->Update(aUpperBox, GetSlideAspectRatio());
815     mpLayout->SetupVisibleArea();
816     mpLayout->UpdateScrollBars();
817 
818     // Tell the preview cache about some of the values.
819     mxPreviewCache->setPreviewSize(mpLayout->maPreviewSize);
820     mxPreviewCache->setVisibleRange(
821         mpLayout->GetFirstVisibleSlideIndex(),
822         mpLayout->GetLastVisibleSlideIndex());
823 
824     // Clear the frame polygon so that it is re-created on the next paint.
825     mxPreviewFrame = NULL;
826 }
827 
828 
829 
830 
PlaceScrollBars(const geometry::RealRectangle2D & rUpperBox)831 geometry::RealRectangle2D PresenterSlideSorter::PlaceScrollBars (
832     const geometry::RealRectangle2D& rUpperBox)
833 {
834     mpLayout->Update(rUpperBox, GetSlideAspectRatio());
835     bool bIsScrollBarNeeded (false);
836     Reference<container::XIndexAccess> xSlides (mxSlideShowController, UNO_QUERY_THROW);
837     if (xSlides.is())
838         bIsScrollBarNeeded = mpLayout->IsScrollBarNeeded(xSlides->getCount());
839 
840     if (mpLayout->GetOrientation() == Layout::Vertical)
841     {
842         if (mpVerticalScrollBar.get() != NULL)
843         {
844             if (bIsScrollBarNeeded)
845             {
846                 // Place vertical scroll bar at right border.
847                 mpVerticalScrollBar->SetPosSize(geometry::RealRectangle2D(
848                     rUpperBox.X2 - mpVerticalScrollBar->GetSize(),
849                     rUpperBox.Y1,
850                     rUpperBox.X2,
851                     rUpperBox.Y2));
852                 mpVerticalScrollBar->SetVisible(true);
853 
854                 // Reduce area covered by the scroll bar from the available
855                 // space.
856                 return geometry::RealRectangle2D(
857                     rUpperBox.X1,
858                     rUpperBox.Y1,
859                     rUpperBox.X2 - mpVerticalScrollBar->GetSize() - gnHorizontalGap,
860                     rUpperBox.Y2);
861             }
862             else
863                 mpVerticalScrollBar->SetVisible(false);
864         }
865     }
866     else
867     {
868         if (mpHorizontalScrollBar.get() != NULL)
869         {
870             if (bIsScrollBarNeeded)
871             {
872                 // Place horixontal scroll bar at the bottom.
873                 mpHorizontalScrollBar->SetPosSize(geometry::RealRectangle2D(
874                     rUpperBox.X1,
875                     rUpperBox.Y2 - mpHorizontalScrollBar->GetSize(),
876                     rUpperBox.X2,
877                     rUpperBox.Y2));
878                 mpHorizontalScrollBar->SetVisible(true);
879 
880                 // Reduce area covered by the scroll bar from the available
881                 // space.
882                 return geometry::RealRectangle2D(
883                     rUpperBox.X1,
884                     rUpperBox.Y1,
885                     rUpperBox.X2,
886                     rUpperBox.Y2 - mpHorizontalScrollBar->GetSize() - gnVerticalGap);
887             }
888             else
889             mpHorizontalScrollBar->SetVisible(false);
890         }
891     }
892 
893     return rUpperBox;
894 }
895 
896 
897 
898 
PlaceCloseButton(const PresenterPaneContainer::SharedPaneDescriptor & rpPane,const awt::Rectangle & rCenterBox,const sal_Int32 nLeftBorderWidth)899 void PresenterSlideSorter::PlaceCloseButton (
900     const PresenterPaneContainer::SharedPaneDescriptor& rpPane,
901     const awt::Rectangle& rCenterBox,
902     const sal_Int32 nLeftBorderWidth)
903 {
904     // Place button.  When the callout is near the center then the button is
905     // centered over the callout.  Otherwise it is centered with respect to
906     // the whole window.
907     sal_Int32 nCloseButtonCenter (rCenterBox.Width/2);
908     if (rpPane.get() != NULL && rpPane->mxPane.is())
909     {
910         const sal_Int32 nCalloutCenter (rpPane->mxPane->GetCalloutAnchor().X - nLeftBorderWidth);
911         const sal_Int32 nDistanceFromWindowCenter (abs(nCalloutCenter - rCenterBox.Width/2));
912         const sal_Int32 nButtonWidth (mpCloseButton->GetSize().Width);
913         const static sal_Int32 nMaxDistanceForCalloutCentering (nButtonWidth * 2);
914         if (nDistanceFromWindowCenter < nMaxDistanceForCalloutCentering)
915         {
916             if (nCalloutCenter < nButtonWidth/2)
917                 nCloseButtonCenter = nButtonWidth/2;
918             else if (nCalloutCenter > rCenterBox.Width-nButtonWidth/2)
919                 nCloseButtonCenter = rCenterBox.Width-nButtonWidth/2;
920             else
921                 nCloseButtonCenter = nCalloutCenter;
922         }
923     }
924     mpCloseButton->SetCenter(geometry::RealPoint2D(
925         nCloseButtonCenter,
926         rCenterBox.Height - mpCloseButton->GetSize().Height/ 2));
927 }
928 
929 
930 
931 
ClearBackground(const Reference<rendering::XCanvas> & rxCanvas,const awt::Rectangle & rUpdateBox)932 void PresenterSlideSorter::ClearBackground (
933     const Reference<rendering::XCanvas>& rxCanvas,
934     const awt::Rectangle& rUpdateBox)
935 {
936     OSL_ASSERT(rxCanvas.is());
937 
938     const awt::Rectangle aWindowBox (mxWindow->getPosSize());
939     mpPresenterController->GetCanvasHelper()->Paint(
940         mpPresenterController->GetViewBackground(mxViewId->getResourceURL()),
941         rxCanvas,
942         rUpdateBox,
943         awt::Rectangle(0,0,aWindowBox.Width,aWindowBox.Height),
944         awt::Rectangle());
945 }
946 
947 
948 
949 
GetSlideAspectRatio(void) const950 double PresenterSlideSorter::GetSlideAspectRatio (void) const
951 {
952     double nSlideAspectRatio (28.0/21.0);
953 
954     try
955     {
956         Reference<container::XIndexAccess> xSlides(mxSlideShowController, UNO_QUERY_THROW);
957         if (mxSlideShowController.is() && xSlides->getCount()>0)
958         {
959             Reference<beans::XPropertySet> xProperties(xSlides->getByIndex(0),UNO_QUERY_THROW);
960             sal_Int32 nWidth (28000);
961             sal_Int32 nHeight (21000);
962             if ((xProperties->getPropertyValue(OUString::createFromAscii("Width")) >>= nWidth)
963                 && (xProperties->getPropertyValue(OUString::createFromAscii("Height")) >>= nHeight)
964                 && nHeight > 0)
965             {
966                 nSlideAspectRatio = double(nWidth) / double(nHeight);
967             }
968         }
969     }
970     catch (RuntimeException&)
971     {
972         OSL_ASSERT(false);
973     }
974 
975     return nSlideAspectRatio;
976 }
977 
978 
979 
980 
GetPreview(const sal_Int32 nSlideIndex)981 Reference<rendering::XBitmap> PresenterSlideSorter::GetPreview (const sal_Int32 nSlideIndex)
982 {
983     if (nSlideIndex < 0 || nSlideIndex>=mpLayout->mnSlideCount)
984         return NULL;
985     else if (mxPane.is())
986         return mxPreviewCache->getSlidePreview(nSlideIndex, mxPane->getCanvas());
987     else
988         return NULL;
989 }
990 
991 
992 
993 
PaintPreview(const Reference<rendering::XCanvas> & rxCanvas,const css::awt::Rectangle & rUpdateBox,const sal_Int32 nSlideIndex)994 void PresenterSlideSorter::PaintPreview (
995     const Reference<rendering::XCanvas>& rxCanvas,
996     const css::awt::Rectangle& rUpdateBox,
997     const sal_Int32 nSlideIndex)
998 {
999     OSL_ASSERT(rxCanvas.is());
1000 
1001     geometry::IntegerSize2D aSize (mpLayout->maPreviewSize);
1002 
1003     if (PresenterGeometryHelper::AreRectanglesDisjoint(
1004         rUpdateBox,
1005         mpLayout->GetBoundingBox(nSlideIndex)))
1006     {
1007         return;
1008     }
1009 
1010     Reference<rendering::XBitmap> xPreview (GetPreview(nSlideIndex));
1011 
1012     const geometry::RealPoint2D aTopLeft (
1013         mpLayout->GetWindowPosition(
1014             mpLayout->GetPoint(nSlideIndex, -1, -1)));
1015 
1016     // Create clip rectangle as intersection of the current update area and
1017     // the bounding box of all previews.
1018     geometry::RealRectangle2D aBoundingBox (mpLayout->maBoundingBox);
1019     aBoundingBox.Y2 += 1;
1020     const geometry::RealRectangle2D aClipBox (
1021         PresenterGeometryHelper::Intersection(
1022             PresenterGeometryHelper::ConvertRectangle(rUpdateBox),
1023             aBoundingBox));
1024     Reference<rendering::XPolyPolygon2D> xClip (
1025         PresenterGeometryHelper::CreatePolygon(aClipBox, rxCanvas->getDevice()));
1026 
1027     const rendering::ViewState aViewState (geometry::AffineMatrix2D(1,0,0, 0,1,0), xClip);
1028 
1029 
1030     rendering::RenderState aRenderState (
1031         geometry::AffineMatrix2D(
1032             1, 0, aTopLeft.X,
1033             0, 1, aTopLeft.Y),
1034         NULL,
1035         Sequence<double>(4),
1036         rendering::CompositeOperation::SOURCE);
1037 
1038 
1039     // Emphasize the current slide.
1040     if (nSlideIndex == mnCurrentSlideIndex)
1041     {
1042         if (mpCurrentSlideFrameRenderer.get() != NULL)
1043         {
1044             const awt::Rectangle aSlideBoundingBox(
1045                 sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.X),
1046                 sal::static_int_cast<sal_Int32>(0.5 + aTopLeft.Y),
1047                 aSize.Width,
1048                 aSize.Height);
1049             maCurrentSlideFrameBoundingBox
1050                 = mpCurrentSlideFrameRenderer->GetBoundingBox(aSlideBoundingBox);
1051             mpCurrentSlideFrameRenderer->PaintCurrentSlideFrame (
1052                 aSlideBoundingBox,
1053                 mxCanvas,
1054                 aClipBox);
1055         }
1056     }
1057 
1058     // Paint the preview.
1059     if (xPreview.is())
1060     {
1061         aSize = xPreview->getSize();
1062         if (aSize.Width > 0 && aSize.Height > 0)
1063         {
1064             rxCanvas->drawBitmap(xPreview, aViewState, aRenderState);
1065         }
1066     }
1067 
1068     // Create a polygon that is used to paint a frame around previews.  Its
1069     // coordinates are chosen in the local coordinate system of a preview.
1070     if ( ! mxPreviewFrame.is())
1071         mxPreviewFrame = PresenterGeometryHelper::CreatePolygon(
1072             awt::Rectangle(-1, -1, aSize.Width+2, aSize.Height+2),
1073             rxCanvas->getDevice());
1074 
1075     // Paint a border around the preview.
1076     if (mxPreviewFrame.is())
1077     {
1078         const geometry::RealRectangle2D aBox (0, 0, aSize.Width, aSize.Height);
1079         const util::Color aFrameColor (0x00000000);
1080         PresenterCanvasHelper::SetDeviceColor(aRenderState, aFrameColor);
1081         rxCanvas->drawPolyPolygon(mxPreviewFrame, aViewState, aRenderState);
1082     }
1083 
1084     // Paint mouse over effect.
1085     mpMouseOverManager->Paint(nSlideIndex, mxCanvas, xClip);
1086 }
1087 
1088 
1089 
1090 
Paint(const awt::Rectangle & rUpdateBox)1091 void PresenterSlideSorter::Paint (const awt::Rectangle& rUpdateBox)
1092 {
1093     const bool bCanvasChanged ( ! mxCanvas.is());
1094     if ( ! ProvideCanvas())
1095         return;
1096 
1097     if (mpLayout->mnRowCount<=0 || mpLayout->mnColumnCount<=0)
1098     {
1099         OSL_ASSERT(mpLayout->mnRowCount>0 || mpLayout->mnColumnCount>0);
1100         return;
1101     }
1102 
1103     mbIsPaintPending = false;
1104 
1105     ClearBackground(mxCanvas, rUpdateBox);
1106 
1107     // Give the canvas to the controls.
1108     if (bCanvasChanged)
1109     {
1110         if (mpHorizontalScrollBar.is())
1111             mpHorizontalScrollBar->SetCanvas(mxCanvas);
1112         if (mpVerticalScrollBar.is())
1113             mpVerticalScrollBar->SetCanvas(mxCanvas);
1114         if (mpCloseButton.is())
1115             mpCloseButton->SetCanvas(mxCanvas, mxWindow);
1116     }
1117 
1118     // Now that the controls have a canvas we can do the layouting.
1119     if (mbIsLayoutPending)
1120         UpdateLayout();
1121 
1122     // Paint the horizontal separator.
1123     rendering::RenderState aRenderState (geometry::AffineMatrix2D(1,0,0, 0,1,0),
1124             NULL, Sequence<double>(4), rendering::CompositeOperation::SOURCE);
1125     PresenterCanvasHelper::SetDeviceColor(aRenderState, maSeparatorColor);
1126     mxCanvas->drawLine(
1127         geometry::RealPoint2D(0, mnSeparatorY),
1128         geometry::RealPoint2D(mxWindow->getPosSize().Width, mnSeparatorY),
1129         rendering::ViewState(geometry::AffineMatrix2D(1,0,0, 0,1,0), NULL),
1130         aRenderState);
1131 
1132     // Paint the slides.
1133     if ( ! PresenterGeometryHelper::AreRectanglesDisjoint(
1134         rUpdateBox,
1135         PresenterGeometryHelper::ConvertRectangle(mpLayout->maBoundingBox)))
1136     {
1137         mpLayout->ForAllVisibleSlides(
1138             ::boost::bind(&PresenterSlideSorter::PaintPreview, this, mxCanvas, rUpdateBox, _1));
1139     }
1140 
1141     Reference<rendering::XSpriteCanvas> xSpriteCanvas (mxCanvas, UNO_QUERY);
1142     if (xSpriteCanvas.is())
1143         xSpriteCanvas->updateScreen(sal_False);
1144 }
1145 
1146 
1147 
1148 
SetHorizontalOffset(const double nXOffset)1149 void PresenterSlideSorter::SetHorizontalOffset (const double nXOffset)
1150 {
1151     if (mpLayout->SetHorizontalOffset(nXOffset))
1152     {
1153         mxPreviewCache->setVisibleRange(
1154             mpLayout->GetFirstVisibleSlideIndex(),
1155             mpLayout->GetLastVisibleSlideIndex());
1156 
1157         mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1158     }
1159 }
1160 
1161 
1162 
1163 
SetVerticalOffset(const double nYOffset)1164 void PresenterSlideSorter::SetVerticalOffset (const double nYOffset)
1165 {
1166     if (mpLayout->SetVerticalOffset(nYOffset))
1167     {
1168         mxPreviewCache->setVisibleRange(
1169             mpLayout->GetFirstVisibleSlideIndex(),
1170             mpLayout->GetLastVisibleSlideIndex());
1171 
1172         mpPresenterController->GetPaintManager()->Invalidate(mxWindow);
1173     }
1174 }
1175 
1176 
1177 
1178 
GotoSlide(const sal_Int32 nSlideIndex)1179 void PresenterSlideSorter::GotoSlide (const sal_Int32 nSlideIndex)
1180 {
1181     mxSlideShowController->gotoSlideIndex(nSlideIndex);
1182     mpPresenterController->HideSlideSorter();
1183 }
1184 
1185 
1186 
1187 
ProvideCanvas(void)1188 bool PresenterSlideSorter::ProvideCanvas (void)
1189 {
1190     if ( ! mxCanvas.is())
1191     {
1192         if (mxPane.is())
1193             mxCanvas = mxPane->getCanvas();
1194 
1195         // Register as event listener so that we are informed when the
1196         // canvas is disposed (and we have to fetch another one).
1197         Reference<lang::XComponent> xComponent (mxCanvas, UNO_QUERY);
1198         if (xComponent.is())
1199             xComponent->addEventListener(static_cast<awt::XWindowListener*>(this));
1200 
1201         // Tell the scrollbar about the canvas.
1202         if (mpHorizontalScrollBar.is())
1203             mpHorizontalScrollBar->SetCanvas(mxCanvas);
1204 
1205         mpCurrentSlideFrameRenderer.reset(
1206             new CurrentSlideFrameRenderer(mxComponentContext, mxCanvas));
1207     }
1208     return mxCanvas.is();
1209 }
1210 
1211 
1212 
1213 
ThrowIfDisposed(void)1214 void PresenterSlideSorter::ThrowIfDisposed (void)
1215 {
1216     if (rBHelper.bDisposed || rBHelper.bInDispose)
1217     {
1218         throw lang::DisposedException (
1219             OUString(RTL_CONSTASCII_USTRINGPARAM(
1220                 "PresenterSlideSorter has been already disposed")),
1221             const_cast<uno::XWeak*>(static_cast<const uno::XWeak*>(this)));
1222     }
1223 }
1224 
1225 
1226 
1227 
1228 //===== PresenterSlideSorter::Layout ==========================================
1229 
Layout(const Orientation eOrientation,const::rtl::Reference<PresenterScrollBar> & rpHorizontalScrollBar,const::rtl::Reference<PresenterScrollBar> & rpVerticalScrollBar)1230 PresenterSlideSorter::Layout::Layout (
1231     const Orientation eOrientation,
1232     const ::rtl::Reference<PresenterScrollBar>& rpHorizontalScrollBar,
1233     const ::rtl::Reference<PresenterScrollBar>& rpVerticalScrollBar)
1234     : maBoundingBox(),
1235       maPreviewSize(),
1236       mnHorizontalOffset(0),
1237       mnVerticalOffset(0),
1238       mnHorizontalGap(0),
1239       mnVerticalGap(0),
1240       mnHorizontalBorder(0),
1241       mnVerticalBorder(0),
1242       mnRowCount(1),
1243       mnColumnCount(1),
1244       mnSlideCount(0),
1245       mnSlideIndexAtMouse(-1),
1246       mnFirstVisibleColumn(-1),
1247       mnLastVisibleColumn(-1),
1248       mnFirstVisibleRow(-1),
1249       mnLastVisibleRow(-1),
1250       meOrientation(eOrientation),
1251       mpHorizontalScrollBar(rpHorizontalScrollBar),
1252       mpVerticalScrollBar(rpVerticalScrollBar)
1253 {
1254 }
1255 
1256 
1257 
1258 
Update(const geometry::RealRectangle2D & rBoundingBox,const double nSlideAspectRatio)1259 void PresenterSlideSorter::Layout::Update (
1260     const geometry::RealRectangle2D& rBoundingBox,
1261     const double nSlideAspectRatio)
1262 {
1263     maBoundingBox = rBoundingBox;
1264 
1265     mnHorizontalBorder = gnHorizontalBorder;
1266     mnVerticalBorder = gnVerticalBorder;
1267 
1268     const double nWidth (rBoundingBox.X2 - rBoundingBox.X1 - 2*mnHorizontalBorder);
1269     const double nHeight (rBoundingBox.Y2 - rBoundingBox.Y1 - 2*mnVerticalBorder);
1270     if (nWidth<=0 || nHeight<=0)
1271         return;
1272 
1273     double nPreviewWidth;
1274 
1275     // Determine column count, preview width, and horizontal gap (borders
1276     // are half the gap).  Try to use the preferred values.  Try more to
1277     // stay in the valid intervalls.  This last constraint may be not
1278     // fulfilled in some cases.
1279     const double nElementWidth = nWidth / gnPreferredColumnCount;
1280     if (nElementWidth < gnMinimalPreviewWidth + gnMinimalHorizontalPreviewGap)
1281     {
1282         // The preferred column count is too large.
1283         // Can we use the preferred preview width?
1284         if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1285         {
1286             // Yes.
1287             nPreviewWidth = gnPreferredPreviewWidth;
1288             mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1289                 / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1290             mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1291         }
1292         else
1293         {
1294             // No.  Set the column count to 1 and adapt preview width and
1295             // gap.
1296             mnColumnCount = 1;
1297             mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1298             if (nWidth - gnMinimalHorizontalPreviewGap >= gnPreferredPreviewWidth)
1299                 nPreviewWidth = nWidth - gnMinimalHorizontalPreviewGap;
1300             else
1301                 nPreviewWidth = ::std::max(gnMinimalPreviewWidth, nWidth-mnHorizontalGap);
1302         }
1303     }
1304     else if (nElementWidth > gnMaximalPreviewWidth + gnMaximalHorizontalPreviewGap)
1305     {
1306         // The preferred column count is too small.
1307         nPreviewWidth = gnPreferredPreviewWidth;
1308         mnColumnCount = floor((nWidth+gnPreferredHorizontalPreviewGap)
1309             / (nPreviewWidth+gnPreferredHorizontalPreviewGap));
1310         mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1311     }
1312     else
1313     {
1314         // The preferred column count is possible.  Determine gap and
1315         // preview width.
1316         mnColumnCount = gnPreferredColumnCount;
1317         if (nElementWidth - gnPreferredPreviewWidth < gnMinimalHorizontalPreviewGap)
1318         {
1319             // Use the minimal gap and adapt the preview width.
1320             mnHorizontalGap = floor(gnMinimalHorizontalPreviewGap);
1321             nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1322         }
1323         else if (nElementWidth - gnPreferredPreviewWidth <= gnMaximalHorizontalPreviewGap)
1324         {
1325             // Use the maximal gap and adapt the preview width.
1326             mnHorizontalGap = round(gnMaximalHorizontalPreviewGap);
1327             nPreviewWidth = (nWidth - mnColumnCount*mnHorizontalGap) / mnColumnCount;
1328         }
1329         else
1330         {
1331             // Use the preferred preview width and adapt the gap.
1332             nPreviewWidth = gnPreferredPreviewWidth;
1333             mnHorizontalGap = round((nWidth - mnColumnCount*nPreviewWidth) / mnColumnCount);
1334         }
1335     }
1336 
1337     // Now determine the row count, preview height, and vertical gap.
1338     const double nPreviewHeight = nPreviewWidth / nSlideAspectRatio;
1339     mnRowCount = ::std::max(
1340         sal_Int32(1),
1341         sal_Int32(ceil((nHeight+gnPreferredVerticalPreviewGap)
1342                 / (nPreviewHeight + gnPreferredVerticalPreviewGap))));
1343     mnVerticalGap = round(gnPreferredVerticalPreviewGap);
1344 
1345     maPreviewSize = geometry::IntegerSize2D(floor(nPreviewWidth), floor(nPreviewHeight));
1346 
1347     // Reset the offset.
1348     if (meOrientation == Horizontal)
1349     {
1350         mnVerticalOffset = round(-(nHeight
1351             - mnRowCount*maPreviewSize.Height - (mnRowCount-1)*mnVerticalGap)
1352             / 2);
1353         mnHorizontalOffset = 0;
1354     }
1355     else
1356     {
1357         mnVerticalOffset = 0;
1358         mnHorizontalOffset = round(-(nWidth
1359             - mnColumnCount*maPreviewSize.Width
1360             - (mnColumnCount-1)*mnHorizontalGap)
1361             / 2);
1362     }
1363 }
1364 
1365 
1366 
1367 
SetupVisibleArea(void)1368 void PresenterSlideSorter::Layout::SetupVisibleArea (void)
1369 {
1370     geometry::RealPoint2D aPoint (GetLocalPosition(
1371         geometry::RealPoint2D(maBoundingBox.X1, maBoundingBox.Y1)));
1372     if (meOrientation == Horizontal)
1373     {
1374         mnFirstVisibleColumn = ::std::max(sal_Int32(0), GetColumn(aPoint));
1375         mnFirstVisibleRow = 0;
1376     }
1377     else
1378     {
1379         mnFirstVisibleColumn = 0;
1380         mnFirstVisibleRow = ::std::max(sal_Int32(0), GetRow(aPoint));
1381     }
1382 
1383     aPoint = GetLocalPosition(geometry::RealPoint2D( maBoundingBox.X2, maBoundingBox.Y2));
1384     if (meOrientation == Horizontal)
1385     {
1386         mnLastVisibleColumn = GetColumn(aPoint, true);
1387         mnLastVisibleRow = mnRowCount - 1;
1388     }
1389     else
1390     {
1391         mnLastVisibleColumn = mnColumnCount - 1;
1392         mnLastVisibleRow = GetRow(aPoint, true);
1393     }
1394 }
1395 
1396 
1397 
1398 
IsScrollBarNeeded(const sal_Int32 nSlideCount)1399 bool PresenterSlideSorter::Layout::IsScrollBarNeeded (const sal_Int32 nSlideCount)
1400 {
1401     geometry::RealPoint2D aBottomRight;
1402     if (GetOrientation() == Layout::Vertical)
1403         aBottomRight = GetPoint(
1404             mnColumnCount * (GetRow(nSlideCount)+1) - 1, +1, +1);
1405     else
1406         aBottomRight = GetPoint(
1407             mnRowCount * (GetColumn(nSlideCount)+1) - 1, +1, +1);
1408     return aBottomRight.X > maBoundingBox.X2-maBoundingBox.X1
1409         || aBottomRight.Y > maBoundingBox.Y2-maBoundingBox.Y1;
1410 }
1411 
1412 
1413 
1414 
GetLocalPosition(const geometry::RealPoint2D & rWindowPoint) const1415 geometry::RealPoint2D PresenterSlideSorter::Layout::GetLocalPosition(
1416     const geometry::RealPoint2D& rWindowPoint) const
1417 {
1418     return css::geometry::RealPoint2D(
1419         rWindowPoint.X - maBoundingBox.X1 + mnHorizontalOffset,
1420         rWindowPoint.Y - maBoundingBox.Y1 + mnVerticalOffset);
1421 }
1422 
1423 
1424 
1425 
GetWindowPosition(const geometry::RealPoint2D & rLocalPoint) const1426 geometry::RealPoint2D PresenterSlideSorter::Layout::GetWindowPosition(
1427     const geometry::RealPoint2D& rLocalPoint) const
1428 {
1429     return css::geometry::RealPoint2D(
1430         rLocalPoint.X - mnHorizontalOffset + maBoundingBox.X1,
1431         rLocalPoint.Y - mnVerticalOffset + maBoundingBox.Y1);
1432 }
1433 
1434 
1435 
1436 
GetColumn(const css::geometry::RealPoint2D & rLocalPoint,const bool bReturnInvalidValue) const1437 sal_Int32 PresenterSlideSorter::Layout::GetColumn (
1438     const css::geometry::RealPoint2D& rLocalPoint,
1439     const bool bReturnInvalidValue) const
1440 {
1441     const sal_Int32 nColumn(floor(
1442         (rLocalPoint.X + mnHorizontalGap/2.0) / (maPreviewSize.Width+mnHorizontalGap)));
1443     if (bReturnInvalidValue
1444         || (nColumn>=mnFirstVisibleColumn && nColumn<=mnLastVisibleColumn))
1445     {
1446         return nColumn;
1447     }
1448     else
1449         return -1;
1450 }
1451 
1452 
1453 
1454 
GetRow(const css::geometry::RealPoint2D & rLocalPoint,const bool bReturnInvalidValue) const1455 sal_Int32 PresenterSlideSorter::Layout::GetRow (
1456     const css::geometry::RealPoint2D& rLocalPoint,
1457     const bool bReturnInvalidValue) const
1458 {
1459     const sal_Int32 nRow (floor(
1460         (rLocalPoint.Y + mnVerticalGap/2.0) / (maPreviewSize.Height+mnVerticalGap)));
1461     if (bReturnInvalidValue
1462         || (nRow>=mnFirstVisibleRow && nRow<=mnLastVisibleRow))
1463     {
1464         return nRow;
1465     }
1466     else
1467         return -1;
1468 }
1469 
1470 
1471 
1472 
GetSlideIndexForPosition(const css::geometry::RealPoint2D & rWindowPoint) const1473 sal_Int32 PresenterSlideSorter::Layout::GetSlideIndexForPosition (
1474     const css::geometry::RealPoint2D& rWindowPoint) const
1475 {
1476     if ( ! PresenterGeometryHelper::IsInside(maBoundingBox, rWindowPoint))
1477         return -1;
1478 
1479     const css::geometry::RealPoint2D aLocalPosition (GetLocalPosition(rWindowPoint));
1480     const sal_Int32 nColumn (GetColumn(aLocalPosition));
1481     const sal_Int32 nRow (GetRow(aLocalPosition));
1482 
1483     if (nColumn < 0 || nRow < 0)
1484         return -1;
1485     else
1486     {
1487         sal_Int32 nIndex (GetIndex(nRow, nColumn));
1488         if (nIndex >= mnSlideCount)
1489             return -1;
1490         else
1491             return nIndex;
1492     }
1493 }
1494 
1495 
1496 
1497 
GetPoint(const sal_Int32 nSlideIndex,const sal_Int32 nRelativeHorizontalPosition,const sal_Int32 nRelativeVerticalPosition) const1498 geometry::RealPoint2D PresenterSlideSorter::Layout::GetPoint (
1499     const sal_Int32 nSlideIndex,
1500     const sal_Int32 nRelativeHorizontalPosition,
1501     const sal_Int32 nRelativeVerticalPosition) const
1502 {
1503     sal_Int32 nColumn (GetColumn(nSlideIndex));
1504     sal_Int32 nRow (GetRow(nSlideIndex));
1505 
1506     geometry::RealPoint2D aPosition (
1507         mnHorizontalBorder + nColumn*(maPreviewSize.Width+mnHorizontalGap),
1508         mnVerticalBorder + nRow*(maPreviewSize.Height+mnVerticalGap));
1509 
1510     if (nRelativeHorizontalPosition >= 0)
1511     {
1512         if (nRelativeHorizontalPosition > 0)
1513             aPosition.X += maPreviewSize.Width;
1514         else
1515             aPosition.X += maPreviewSize.Width / 2.0;
1516     }
1517     if (nRelativeVerticalPosition >= 0)
1518     {
1519         if (nRelativeVerticalPosition > 0)
1520             aPosition.Y += maPreviewSize.Height;
1521         else
1522             aPosition.Y += maPreviewSize.Height / 2.0;
1523     }
1524 
1525     return aPosition;
1526 }
1527 
1528 
1529 
1530 
GetBoundingBox(const sal_Int32 nSlideIndex) const1531 awt::Rectangle PresenterSlideSorter::Layout::GetBoundingBox (const sal_Int32 nSlideIndex) const
1532 {
1533     const geometry::RealPoint2D aWindowPosition(GetWindowPosition(GetPoint(nSlideIndex, -1, -1)));
1534     return PresenterGeometryHelper::ConvertRectangle(
1535         geometry::RealRectangle2D(
1536             aWindowPosition.X,
1537             aWindowPosition.Y,
1538             aWindowPosition.X + maPreviewSize.Width,
1539             aWindowPosition.Y + maPreviewSize.Height));
1540 }
1541 
1542 
1543 
1544 
ForAllVisibleSlides(const::boost::function<void (sal_Int32)> & rAction)1545 void PresenterSlideSorter::Layout::ForAllVisibleSlides (const ::boost::function<void(sal_Int32)>& rAction)
1546 {
1547     for (sal_Int32 nRow=mnFirstVisibleRow; nRow<=mnLastVisibleRow; ++nRow)
1548     {
1549         for (sal_Int32 nColumn=mnFirstVisibleColumn; nColumn<=mnLastVisibleColumn; ++nColumn)
1550         {
1551             const sal_Int32 nSlideIndex (GetIndex(nRow, nColumn));
1552             if (nSlideIndex >= mnSlideCount)
1553                 return;
1554             rAction(nSlideIndex);
1555         }
1556     }
1557 }
1558 
1559 
1560 
1561 
GetFirstVisibleSlideIndex(void) const1562 sal_Int32 PresenterSlideSorter::Layout::GetFirstVisibleSlideIndex (void) const
1563 {
1564     return GetIndex(mnFirstVisibleRow, mnFirstVisibleColumn);
1565 }
1566 
1567 
1568 
1569 
GetLastVisibleSlideIndex(void) const1570 sal_Int32 PresenterSlideSorter::Layout::GetLastVisibleSlideIndex (void) const
1571 {
1572     return ::std::min(
1573         GetIndex(mnLastVisibleRow, mnLastVisibleColumn),
1574         mnSlideCount);
1575 }
1576 
1577 
1578 
1579 
SetHorizontalOffset(const double nOffset)1580 bool PresenterSlideSorter::Layout::SetHorizontalOffset (const double nOffset)
1581 {
1582     if (mnHorizontalOffset != nOffset)
1583     {
1584         mnHorizontalOffset = round(nOffset);
1585         SetupVisibleArea();
1586         UpdateScrollBars();
1587         return true;
1588     }
1589     else
1590         return false;
1591 }
1592 
1593 
1594 
1595 
SetVerticalOffset(const double nOffset)1596 bool PresenterSlideSorter::Layout::SetVerticalOffset (const double nOffset)
1597 {
1598     if (mnVerticalOffset != nOffset)
1599     {
1600         mnVerticalOffset = round(nOffset);
1601         SetupVisibleArea();
1602         UpdateScrollBars();
1603         return true;
1604     }
1605     else
1606         return false;
1607 }
1608 
1609 
1610 
1611 
1612 PresenterSlideSorter::Layout::Orientation
GetOrientation(void) const1613     PresenterSlideSorter::Layout::GetOrientation (void) const
1614 {
1615     return meOrientation;
1616 }
1617 
1618 
1619 
1620 
UpdateScrollBars(void)1621 void PresenterSlideSorter::Layout::UpdateScrollBars (void)
1622 {
1623     sal_Int32 nTotalColumnCount (0);
1624     sal_Int32 nTotalRowCount (0);
1625     if (meOrientation == Horizontal)
1626     {
1627         nTotalColumnCount = sal_Int32(ceil(double(mnSlideCount) / double(mnRowCount)));
1628         nTotalRowCount = mnRowCount;
1629     }
1630     else
1631     {
1632         nTotalColumnCount = mnColumnCount;
1633         nTotalRowCount = sal_Int32(ceil(double(mnSlideCount) / double(mnColumnCount)));
1634     }
1635 
1636     if (mpHorizontalScrollBar.get() != NULL)
1637     {
1638         mpHorizontalScrollBar->SetTotalSize(
1639             nTotalColumnCount * maPreviewSize.Width
1640             + (nTotalColumnCount-1) * mnHorizontalGap
1641             + 2*mnHorizontalBorder);
1642         mpHorizontalScrollBar->SetThumbPosition(mnHorizontalOffset, false);
1643         mpHorizontalScrollBar->SetThumbSize(maBoundingBox.X2 - maBoundingBox.X1 + 1);
1644         mpHorizontalScrollBar->SetLineHeight(maPreviewSize.Width);
1645     }
1646     if (mpVerticalScrollBar.get() != NULL)
1647     {
1648         mpVerticalScrollBar->SetTotalSize(
1649             nTotalRowCount * maPreviewSize.Height
1650                 + (nTotalRowCount-1) * mnVerticalGap
1651             + 2*mnVerticalGap);
1652         mpVerticalScrollBar->SetThumbPosition(mnVerticalOffset, false);
1653         mpVerticalScrollBar->SetThumbSize(maBoundingBox.Y2 - maBoundingBox.Y1 + 1);
1654         mpVerticalScrollBar->SetLineHeight(maPreviewSize.Height);
1655     }
1656 
1657 
1658 
1659     // No place yet for the vertical scroll bar.
1660 }
1661 
1662 
1663 
1664 
GetIndex(const sal_Int32 nRow,const sal_Int32 nColumn) const1665 sal_Int32 PresenterSlideSorter::Layout::GetIndex (
1666     const sal_Int32 nRow,
1667     const sal_Int32 nColumn) const
1668 {
1669     if (meOrientation == Horizontal)
1670         return nColumn * mnRowCount + nRow;
1671     else
1672         return nRow * mnColumnCount + nColumn;
1673 }
1674 
1675 
1676 
1677 
GetRow(const sal_Int32 nSlideIndex) const1678 sal_Int32 PresenterSlideSorter::Layout::GetRow (const sal_Int32 nSlideIndex) const
1679 {
1680     if (meOrientation == Horizontal)
1681         return nSlideIndex % mnRowCount;
1682     else
1683         return nSlideIndex / mnColumnCount;
1684 }
1685 
1686 
1687 
1688 
GetColumn(const sal_Int32 nSlideIndex) const1689 sal_Int32 PresenterSlideSorter::Layout::GetColumn (const sal_Int32 nSlideIndex) const
1690 {
1691     if (meOrientation == Horizontal)
1692         return nSlideIndex / mnRowCount;
1693     else
1694         return nSlideIndex % mnColumnCount;
1695 }
1696 
1697 
1698 
1699 
1700 //===== PresenterSlideSorter::MouseOverManager ================================
1701 
MouseOverManager(const Reference<container::XIndexAccess> & rxSlides,const::boost::shared_ptr<PresenterTheme> & rpTheme,const Reference<awt::XWindow> & rxInvalidateTarget,const::boost::shared_ptr<PresenterPaintManager> & rpPaintManager)1702 PresenterSlideSorter::MouseOverManager::MouseOverManager (
1703     const Reference<container::XIndexAccess>& rxSlides,
1704     const ::boost::shared_ptr<PresenterTheme>& rpTheme,
1705     const Reference<awt::XWindow>& rxInvalidateTarget,
1706     const ::boost::shared_ptr<PresenterPaintManager>& rpPaintManager)
1707     : mxCanvas(),
1708       mxSlides(rxSlides),
1709       mpLeftLabelBitmap(),
1710       mpCenterLabelBitmap(),
1711       mpRightLabelBitmap(),
1712       mpFont(),
1713       mnSlideIndex(-1),
1714       maSlideBoundingBox(),
1715       mxInvalidateTarget(rxInvalidateTarget),
1716       mpPaintManager(rpPaintManager)
1717 {
1718     if (rpTheme.get()!=NULL)
1719     {
1720         ::boost::shared_ptr<PresenterBitmapContainer> pBitmaps (rpTheme->GetBitmapContainer());
1721         if (pBitmaps.get() != NULL)
1722         {
1723             mpLeftLabelBitmap = pBitmaps->GetBitmap(A2S("LabelLeft"));
1724             mpCenterLabelBitmap = pBitmaps->GetBitmap(A2S("LabelCenter"));
1725             mpRightLabelBitmap = pBitmaps->GetBitmap(A2S("LabelRight"));
1726         }
1727 
1728         mpFont = rpTheme->GetFont(A2S("SlideSorterLabelFont"));
1729     }
1730 }
1731 
1732 
1733 
1734 
~MouseOverManager(void)1735 PresenterSlideSorter::MouseOverManager::~MouseOverManager (void)
1736 {
1737 }
1738 
1739 
1740 
1741 
Paint(const sal_Int32 nSlideIndex,const Reference<rendering::XCanvas> & rxCanvas,const Reference<rendering::XPolyPolygon2D> & rxClip)1742 void PresenterSlideSorter::MouseOverManager::Paint (
1743     const sal_Int32 nSlideIndex,
1744     const Reference<rendering::XCanvas>& rxCanvas,
1745     const Reference<rendering::XPolyPolygon2D>& rxClip)
1746 {
1747     if (nSlideIndex != mnSlideIndex)
1748         return;
1749 
1750     if (mxCanvas != rxCanvas)
1751         SetCanvas(rxCanvas);
1752     if (rxCanvas != NULL)
1753     {
1754         if ( ! mxBitmap.is())
1755             mxBitmap = CreateBitmap(msText, maSlideBoundingBox.Width);
1756         if (mxBitmap.is())
1757         {
1758             geometry::IntegerSize2D aSize (mxBitmap->getSize());
1759             const double nXOffset (maSlideBoundingBox.X
1760                 + (maSlideBoundingBox.Width - aSize.Width) / 2.0);
1761             const double nYOffset (maSlideBoundingBox.Y
1762                 + (maSlideBoundingBox.Height - aSize.Height) / 2.0);
1763             rxCanvas->drawBitmap(
1764                 mxBitmap,
1765                 rendering::ViewState(
1766                     geometry::AffineMatrix2D(1,0,0, 0,1,0),
1767                     rxClip),
1768                 rendering::RenderState(
1769                     geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1770                     NULL,
1771                     Sequence<double>(4),
1772                     rendering::CompositeOperation::SOURCE));
1773         }
1774     }
1775 }
1776 
1777 
1778 
1779 
SetCanvas(const Reference<rendering::XCanvas> & rxCanvas)1780 void PresenterSlideSorter::MouseOverManager::SetCanvas (
1781     const Reference<rendering::XCanvas>& rxCanvas)
1782 {
1783     mxCanvas = rxCanvas;
1784     if (mpFont.get() != NULL)
1785         mpFont->PrepareFont(Reference<rendering::XCanvas>(mxCanvas, UNO_QUERY));
1786 }
1787 
1788 
1789 
1790 
SetSlide(const sal_Int32 nSlideIndex,const awt::Rectangle & rBox)1791 void PresenterSlideSorter::MouseOverManager::SetSlide (
1792     const sal_Int32 nSlideIndex,
1793     const awt::Rectangle& rBox)
1794 {
1795     if (mnSlideIndex == nSlideIndex)
1796         return;
1797 
1798     mnSlideIndex = -1;
1799     Invalidate();
1800 
1801     maSlideBoundingBox = rBox;
1802     mnSlideIndex = nSlideIndex;
1803 
1804     if (nSlideIndex >= 0)
1805     {
1806         if (mxSlides.get() != NULL)
1807         {
1808             msText = OUString();
1809 
1810             Reference<beans::XPropertySet> xSlideProperties(mxSlides->getByIndex(nSlideIndex), UNO_QUERY);
1811             if (xSlideProperties.is())
1812                 xSlideProperties->getPropertyValue(A2S("LinkDisplayName")) >>= msText;
1813 
1814             if (msText.getLength() == 0)
1815                 msText = A2S("Slide ") + OUString::valueOf(nSlideIndex + 1);
1816         }
1817     }
1818     else
1819     {
1820         msText = OUString();
1821     }
1822     mxBitmap = NULL;
1823 
1824     Invalidate();
1825 }
1826 
1827 
1828 
1829 
CreateBitmap(const OUString & rsText,const sal_Int32 nMaximalWidth) const1830 Reference<rendering::XBitmap> PresenterSlideSorter::MouseOverManager::CreateBitmap (
1831     const OUString& rsText,
1832     const sal_Int32 nMaximalWidth) const
1833 {
1834     if ( ! mxCanvas.is())
1835         return NULL;
1836 
1837     if (mpFont.get()==NULL || !mpFont->mxFont.is())
1838         return NULL;
1839 
1840     // Long text has to be shortened.
1841     const OUString sText (GetFittingText(rsText, nMaximalWidth
1842             - 2*gnHorizontalLabelBorder
1843             - 2*gnHorizontalLabelPadding));
1844 
1845     // Determine the size of the label.  Its height is defined by the
1846     // bitmaps that are used to paints its background.  The width is defined
1847     // by the text.
1848     geometry::IntegerSize2D aLabelSize (CalculateLabelSize(sText));
1849 
1850     // Create a new bitmap that will contain the complete label.
1851     Reference<rendering::XBitmap> xBitmap (
1852         mxCanvas->getDevice()->createCompatibleAlphaBitmap(aLabelSize));
1853 
1854     if ( ! xBitmap.is())
1855         return NULL;
1856 
1857     Reference<rendering::XBitmapCanvas> xBitmapCanvas (xBitmap, UNO_QUERY);
1858     if ( ! xBitmapCanvas.is())
1859         return NULL;
1860 
1861     // Paint the background.
1862     PaintButtonBackground(xBitmapCanvas, aLabelSize);
1863 
1864     // Paint the text.
1865     if (sText.getLength() > 0)
1866     {
1867 
1868         const rendering::StringContext aContext (sText, 0, sText.getLength());
1869         const Reference<rendering::XTextLayout> xLayout (mpFont->mxFont->createTextLayout(
1870             aContext, rendering::TextDirection::WEAK_LEFT_TO_RIGHT,0));
1871         const geometry::RealRectangle2D aTextBBox (xLayout->queryTextBounds());
1872 
1873         const double nXOffset = (aLabelSize.Width - aTextBBox.X2 + aTextBBox.X1) / 2;
1874         const double nYOffset = aLabelSize.Height
1875             - (aLabelSize.Height - aTextBBox.Y2 + aTextBBox.Y1)/2 - aTextBBox.Y2;
1876 
1877         const rendering::ViewState aViewState(
1878             geometry::AffineMatrix2D(1,0,0, 0,1,0),
1879             NULL);
1880 
1881         rendering::RenderState aRenderState (
1882             geometry::AffineMatrix2D(1,0,nXOffset, 0,1,nYOffset),
1883             NULL,
1884             Sequence<double>(4),
1885             rendering::CompositeOperation::SOURCE);
1886         PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
1887 
1888         xBitmapCanvas->drawText(
1889             aContext,
1890             mpFont->mxFont,
1891             aViewState,
1892             aRenderState,
1893             rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1894     }
1895 
1896     return xBitmap;
1897 }
1898 
1899 
1900 
1901 
GetFittingText(const OUString & rsText,const double nMaximalWidth) const1902 OUString PresenterSlideSorter::MouseOverManager::GetFittingText (
1903     const OUString& rsText,
1904     const double nMaximalWidth) const
1905 {
1906     const double nTextWidth (
1907         PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText).Width);
1908     if (nTextWidth > nMaximalWidth)
1909     {
1910         // Text is too wide.  Shorten it by removing characters from the end
1911         // and replacing them by ellipses.
1912 
1913         // Guess a start value of the final string length.
1914         double nBestWidth (0);
1915         OUString sBestCandidate;
1916         sal_Int32 nLength (round(rsText.getLength() * nMaximalWidth / nTextWidth));
1917         const OUString sEllipses (A2S("..."));
1918         while (true)
1919         {
1920             const OUString sCandidate (rsText.copy(0,nLength) + sEllipses);
1921             const double nWidth (
1922                 PresenterCanvasHelper::GetTextSize(mpFont->mxFont, sCandidate).Width);
1923             if (nWidth > nMaximalWidth)
1924             {
1925                 // Candidate still too wide, shorten it.
1926                 nLength -= 1;
1927                 if (nLength <= 0)
1928                     break;
1929             }
1930             else if (nWidth < nMaximalWidth)
1931             {
1932                 // Candidate short enough.
1933                 if (nWidth > nBestWidth)
1934                 {
1935                     // Best length so far.
1936                     sBestCandidate = sCandidate;
1937                     nBestWidth = nWidth;
1938                     nLength += 1;
1939                     if (nLength >= rsText.getLength())
1940                         break;
1941                 }
1942                 else
1943                     break;
1944             }
1945             else
1946             {
1947                 // Candidate is exactly as long as it may be.  Use it
1948                 // without looking any further.
1949                 sBestCandidate = sCandidate;
1950                 break;
1951             }
1952         }
1953         return sBestCandidate;
1954     }
1955     else
1956         return rsText;
1957 }
1958 
1959 
1960 
1961 
CalculateLabelSize(const OUString & rsText) const1962 geometry::IntegerSize2D PresenterSlideSorter::MouseOverManager::CalculateLabelSize (
1963     const OUString& rsText) const
1964 {
1965     // Height is specified by the label bitmaps.
1966     sal_Int32 nHeight (32);
1967     if (mpCenterLabelBitmap.get() != NULL)
1968     {
1969         Reference<rendering::XBitmap> xBitmap (mpCenterLabelBitmap->GetNormalBitmap());
1970         if (xBitmap.is())
1971             nHeight = xBitmap->getSize().Height;
1972     }
1973 
1974     // Width is specified by text width and maximal width.
1975     const geometry::RealSize2D aTextSize (
1976         PresenterCanvasHelper::GetTextSize(mpFont->mxFont, rsText));
1977 
1978     const sal_Int32 nWidth (round(aTextSize.Width + 2*gnHorizontalLabelPadding));
1979 
1980     return geometry::IntegerSize2D(nWidth, nHeight);
1981 }
1982 
1983 
1984 
1985 
PaintButtonBackground(const Reference<rendering::XBitmapCanvas> & rxCanvas,const geometry::IntegerSize2D & rSize) const1986 void PresenterSlideSorter::MouseOverManager::PaintButtonBackground (
1987     const Reference<rendering::XBitmapCanvas>& rxCanvas,
1988     const geometry::IntegerSize2D& rSize) const
1989 {
1990     // Get the bitmaps for painting the label background.
1991     Reference<rendering::XBitmap> xLeftLabelBitmap;
1992     if (mpLeftLabelBitmap.get() != NULL)
1993         xLeftLabelBitmap = mpLeftLabelBitmap->GetNormalBitmap();
1994 
1995     Reference<rendering::XBitmap> xCenterLabelBitmap;
1996     if (mpCenterLabelBitmap.get() != NULL)
1997         xCenterLabelBitmap = mpCenterLabelBitmap->GetNormalBitmap();
1998 
1999     Reference<rendering::XBitmap> xRightLabelBitmap;
2000     if (mpRightLabelBitmap.get() != NULL)
2001         xRightLabelBitmap = mpRightLabelBitmap->GetNormalBitmap();
2002 
2003     PresenterUIPainter::PaintHorizontalBitmapComposite (
2004         Reference<rendering::XCanvas>(rxCanvas, UNO_QUERY),
2005         awt::Rectangle(0,0, rSize.Width,rSize.Height),
2006         awt::Rectangle(0,0, rSize.Width,rSize.Height),
2007         xLeftLabelBitmap,
2008         xCenterLabelBitmap,
2009         xRightLabelBitmap);
2010 }
2011 
2012 
2013 
2014 
Invalidate(void)2015 void PresenterSlideSorter::MouseOverManager::Invalidate (void)
2016 {
2017     if (mpPaintManager.get() != NULL)
2018         mpPaintManager->Invalidate(mxInvalidateTarget, maSlideBoundingBox, true);
2019 }
2020 
2021 
2022 
2023 
2024 //===== PresenterSlideSorter::CurrentSlideFrameRenderer =======================
2025 
CurrentSlideFrameRenderer(const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::rendering::XCanvas> & rxCanvas)2026 PresenterSlideSorter::CurrentSlideFrameRenderer::CurrentSlideFrameRenderer (
2027     const css::uno::Reference<css::uno::XComponentContext>& rxContext,
2028     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas)
2029     : mpTopLeft(),
2030       mpTop(),
2031       mpTopRight(),
2032       mpLeft(),
2033       mpRight(),
2034       mpBottomLeft(),
2035       mpBottom(),
2036       mpBottomRight(),
2037       mnTopFrameSize(0),
2038       mnLeftFrameSize(0),
2039       mnRightFrameSize(0),
2040       mnBottomFrameSize(0)
2041 {
2042     PresenterConfigurationAccess aConfiguration (
2043         rxContext,
2044         OUString::createFromAscii("/org.openoffice.Office.PresenterScreen/"),
2045         PresenterConfigurationAccess::READ_ONLY);
2046     Reference<container::XHierarchicalNameAccess> xBitmaps (
2047         aConfiguration.GetConfigurationNode(
2048             A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps")),
2049         UNO_QUERY);
2050     if ( ! xBitmaps.is())
2051         return;
2052 
2053     PresenterBitmapContainer aContainer (
2054         A2S("PresenterScreenSettings/SlideSorter/CurrentSlideBorderBitmaps"),
2055         ::boost::shared_ptr<PresenterBitmapContainer>(),
2056         rxContext,
2057         rxCanvas);
2058 
2059     mpTopLeft = aContainer.GetBitmap(A2S("TopLeft"));
2060     mpTop = aContainer.GetBitmap(A2S("Top"));
2061     mpTopRight = aContainer.GetBitmap(A2S("TopRight"));
2062     mpLeft = aContainer.GetBitmap(A2S("Left"));
2063     mpRight = aContainer.GetBitmap(A2S("Right"));
2064     mpBottomLeft = aContainer.GetBitmap(A2S("BottomLeft"));
2065     mpBottom = aContainer.GetBitmap(A2S("Bottom"));
2066     mpBottomRight = aContainer.GetBitmap(A2S("BottomRight"));
2067 
2068     // Determine size of frame.
2069     if (mpTop.get() != NULL)
2070         mnTopFrameSize = mpTop->mnHeight;
2071     if (mpLeft.get() != NULL)
2072         mnLeftFrameSize = mpLeft->mnWidth;
2073     if (mpRight.get() != NULL)
2074         mnRightFrameSize = mpRight->mnWidth;
2075     if (mpBottom.get() != NULL)
2076         mnBottomFrameSize = mpBottom->mnHeight;
2077 
2078     if (mpTopLeft.get() != NULL)
2079     {
2080         mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopLeft->mnHeight);
2081         mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpTopLeft->mnWidth);
2082     }
2083     if (mpTopRight.get() != NULL)
2084     {
2085         mnTopFrameSize = ::std::max(mnTopFrameSize, mpTopRight->mnHeight);
2086         mnRightFrameSize = ::std::max(mnRightFrameSize, mpTopRight->mnWidth);
2087     }
2088     if (mpBottomLeft.get() != NULL)
2089     {
2090         mnLeftFrameSize = ::std::max(mnLeftFrameSize, mpBottomLeft->mnWidth);
2091         mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomLeft->mnHeight);
2092     }
2093     if (mpBottomRight.get() != NULL)
2094     {
2095         mnRightFrameSize = ::std::max(mnRightFrameSize, mpBottomRight->mnWidth);
2096         mnBottomFrameSize = ::std::max(mnBottomFrameSize, mpBottomRight->mnHeight);
2097     }
2098 }
2099 
2100 
2101 
2102 
~CurrentSlideFrameRenderer(void)2103 PresenterSlideSorter::CurrentSlideFrameRenderer::~CurrentSlideFrameRenderer (void)
2104 {
2105 }
2106 
2107 
2108 
2109 
PaintCurrentSlideFrame(const awt::Rectangle & rSlideBoundingBox,const Reference<rendering::XCanvas> & rxCanvas,const geometry::RealRectangle2D & rClipBox)2110 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintCurrentSlideFrame (
2111     const awt::Rectangle& rSlideBoundingBox,
2112     const Reference<rendering::XCanvas>& rxCanvas,
2113     const geometry::RealRectangle2D& rClipBox)
2114 {
2115     if ( ! rxCanvas.is())
2116         return;
2117 
2118     const Reference<rendering::XPolyPolygon2D> xClip (
2119         PresenterGeometryHelper::CreatePolygon(rClipBox, rxCanvas->getDevice()));
2120 
2121     if (mpTop.get() != NULL)
2122     {
2123         PaintBitmapTiled(
2124             mpTop->GetNormalBitmap(),
2125             rxCanvas,
2126             rClipBox,
2127             rSlideBoundingBox.X,
2128             rSlideBoundingBox.Y - mpTop->mnHeight,
2129             rSlideBoundingBox.Width,
2130             mpTop->mnHeight);
2131     }
2132     if (mpLeft.get() != NULL)
2133     {
2134         PaintBitmapTiled(
2135             mpLeft->GetNormalBitmap(),
2136             rxCanvas,
2137             rClipBox,
2138             rSlideBoundingBox.X - mpLeft->mnWidth,
2139             rSlideBoundingBox.Y,
2140             mpLeft->mnWidth,
2141             rSlideBoundingBox.Height);
2142     }
2143     if (mpRight.get() != NULL)
2144     {
2145         PaintBitmapTiled(
2146             mpRight->GetNormalBitmap(),
2147             rxCanvas,
2148             rClipBox,
2149             rSlideBoundingBox.X + rSlideBoundingBox.Width,
2150             rSlideBoundingBox.Y,
2151             mpRight->mnWidth,
2152             rSlideBoundingBox.Height);
2153     }
2154     if (mpBottom.get() != NULL)
2155     {
2156         PaintBitmapTiled(
2157             mpBottom->GetNormalBitmap(),
2158             rxCanvas,
2159             rClipBox,
2160             rSlideBoundingBox.X,
2161             rSlideBoundingBox.Y + rSlideBoundingBox.Height,
2162             rSlideBoundingBox.Width,
2163             mpBottom->mnHeight);
2164     }
2165     if (mpTopLeft.get() != NULL)
2166     {
2167         PaintBitmapOnce(
2168             mpTopLeft->GetNormalBitmap(),
2169             rxCanvas,
2170             xClip,
2171             rSlideBoundingBox.X - mpTopLeft->mnWidth,
2172             rSlideBoundingBox.Y - mpTopLeft->mnHeight);
2173     }
2174     if (mpTopRight.get() != NULL)
2175     {
2176         PaintBitmapOnce(
2177             mpTopRight->GetNormalBitmap(),
2178             rxCanvas,
2179             xClip,
2180             rSlideBoundingBox.X + rSlideBoundingBox.Width,
2181             rSlideBoundingBox.Y - mpTopLeft->mnHeight);
2182     }
2183     if (mpBottomLeft.get() != NULL)
2184     {
2185         PaintBitmapOnce(
2186             mpBottomLeft->GetNormalBitmap(),
2187             rxCanvas,
2188             xClip,
2189             rSlideBoundingBox.X - mpBottomLeft->mnWidth,
2190             rSlideBoundingBox.Y + rSlideBoundingBox.Height);
2191     }
2192     if (mpBottomRight.get() != NULL)
2193     {
2194         PaintBitmapOnce(
2195             mpBottomRight->GetNormalBitmap(),
2196             rxCanvas,
2197             xClip,
2198             rSlideBoundingBox.X + rSlideBoundingBox.Width,
2199             rSlideBoundingBox.Y + rSlideBoundingBox.Height);
2200     }
2201 }
2202 
2203 
2204 
2205 
GetBoundingBox(const awt::Rectangle & rSlideBoundingBox)2206 awt::Rectangle PresenterSlideSorter::CurrentSlideFrameRenderer::GetBoundingBox (
2207     const awt::Rectangle& rSlideBoundingBox)
2208 {
2209     return awt::Rectangle(
2210         rSlideBoundingBox.X - mnLeftFrameSize,
2211         rSlideBoundingBox.Y - mnTopFrameSize,
2212         rSlideBoundingBox.Width + mnLeftFrameSize + mnRightFrameSize,
2213         rSlideBoundingBox.Height + mnTopFrameSize + mnBottomFrameSize);
2214 }
2215 
2216 
2217 
2218 
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)2219 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapOnce(
2220     const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
2221     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
2222     const Reference<rendering::XPolyPolygon2D>& rxClip,
2223     const double nX,
2224     const double nY)
2225 {
2226     OSL_ASSERT(rxCanvas.is());
2227     if ( ! rxBitmap.is())
2228         return;
2229 
2230     const rendering::ViewState aViewState(
2231         geometry::AffineMatrix2D(1,0,0, 0,1,0),
2232         rxClip);
2233 
2234     const rendering::RenderState aRenderState (
2235         geometry::AffineMatrix2D(
2236             1, 0, nX,
2237             0, 1, nY),
2238         NULL,
2239         Sequence<double>(4),
2240         rendering::CompositeOperation::SOURCE);
2241 
2242     rxCanvas->drawBitmap(
2243         rxBitmap,
2244         aViewState,
2245         aRenderState);
2246 }
2247 
2248 
2249 
2250 
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)2251 void PresenterSlideSorter::CurrentSlideFrameRenderer::PaintBitmapTiled(
2252     const css::uno::Reference<css::rendering::XBitmap>& rxBitmap,
2253     const css::uno::Reference<css::rendering::XCanvas>& rxCanvas,
2254     const geometry::RealRectangle2D& rClipBox,
2255     const double nX0,
2256     const double nY0,
2257     const double nWidth,
2258     const double nHeight)
2259 {
2260     OSL_ASSERT(rxCanvas.is());
2261     if ( ! rxBitmap.is())
2262         return;
2263 
2264     geometry::IntegerSize2D aSize (rxBitmap->getSize());
2265 
2266     const rendering::ViewState aViewState(
2267         geometry::AffineMatrix2D(1,0,0, 0,1,0),
2268         PresenterGeometryHelper::CreatePolygon(
2269             PresenterGeometryHelper::Intersection(
2270                 rClipBox,
2271                 geometry::RealRectangle2D(nX0,nY0,nX0+nWidth,nY0+nHeight)),
2272             rxCanvas->getDevice()));
2273 
2274     rendering::RenderState aRenderState (
2275         geometry::AffineMatrix2D(
2276             1, 0, nX0,
2277             0, 1, nY0),
2278         NULL,
2279         Sequence<double>(4),
2280         rendering::CompositeOperation::SOURCE);
2281 
2282     const double nX1 = nX0 + nWidth;
2283     const double nY1 = nY0 + nHeight;
2284     for (double nY=nY0; nY<nY1; nY+=aSize.Height)
2285         for (double nX=nX0; nX<nX1; nX+=aSize.Width)
2286         {
2287             aRenderState.AffineTransform.m02 = nX;
2288             aRenderState.AffineTransform.m12 = nY;
2289             rxCanvas->drawBitmap(
2290                 rxBitmap,
2291                 aViewState,
2292                 aRenderState);
2293         }
2294 }
2295 
2296 } } // end of namespace ::sdext::presenter
2297