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