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