1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2008 by Sun Microsystems, Inc. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * $RCSfile: $ 10 * $Revision: $ 11 * 12 * This file is part of OpenOffice.org. 13 * 14 * OpenOffice.org is free software: you can redistribute it and/or modify 15 * it under the terms of the GNU Lesser General Public License version 3 16 * only, as published by the Free Software Foundation. 17 * 18 * OpenOffice.org is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU Lesser General Public License version 3 for more details 22 * (a copy is included in the LICENSE file that accompanied this code). 23 * 24 * You should have received a copy of the GNU Lesser General Public License 25 * version 3 along with OpenOffice.org. If not, see 26 * <http://www.openoffice.org/license.html> 27 * for a copy of the LGPLv3 License. 28 * 29 ************************************************************************/ 30 31 // MARKER(update_precomp.py): autogen include statement, do not remove 32 #include "precompiled_sd.hxx" 33 34 #include "sddll.hxx" 35 36 #include <com/sun/star/frame/XFrame.hpp> 37 #include <sfx2/imagemgr.hxx> 38 #include <sfx2/viewfrm.hxx> 39 #include <sfx2/bindings.hxx> 40 #include <sfx2/app.hxx> 41 #include <sfx2/request.hxx> 42 #include <sfx2/dispatch.hxx> 43 44 #include <tools/rcid.h> 45 46 #include <vcl/help.hxx> 47 #include <vcl/imagerepository.hxx> 48 #include <vcl/lazydelete.hxx> 49 50 #include <svx/sdrpagewindow.hxx> 51 #include <svx/sdrpaintwindow.hxx> 52 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx> 53 #include <svx/sdr/overlay/overlaybitmapex.hxx> 54 #include <svx/sdr/overlay/overlaymanager.hxx> 55 #include <svx/svxids.hrc> 56 57 #include "view/viewoverlaymanager.hxx" 58 59 #include "res_bmp.hrc" 60 #include "DrawDocShell.hxx" 61 #include "DrawViewShell.hxx" 62 #include "DrawController.hxx" 63 #include "glob.hrc" 64 #include "strings.hrc" 65 #include "sdresid.hxx" 66 #include "EventMultiplexer.hxx" 67 #include "ViewShellManager.hxx" 68 #include "helpids.h" 69 #include "sdpage.hxx" 70 #include "drawdoc.hxx" 71 #include "smarttag.hxx" 72 73 using ::rtl::OUString; 74 using namespace ::com::sun::star::uno; 75 using namespace ::com::sun::star::frame; 76 77 namespace sd { 78 79 class ImageButtonHdl; 80 81 // -------------------------------------------------------------------- 82 83 static sal_uInt16 gButtonSlots[] = { SID_INSERT_TABLE, SID_INSERT_DIAGRAM, SID_INSERT_GRAPHIC, SID_INSERT_AVMEDIA }; 84 static sal_uInt16 gButtonToolTips[] = { STR_INSERT_TABLE, STR_INSERT_CHART, STR_INSERT_PICTURE, STR_INSERT_MOVIE }; 85 86 // -------------------------------------------------------------------- 87 88 static BitmapEx loadImageResource( sal_uInt16 nId ) 89 { 90 SdResId aResId( nId ); 91 aResId.SetRT( RSC_BITMAP ); 92 93 return BitmapEx( aResId ); 94 } 95 96 // -------------------------------------------------------------------- 97 98 static BitmapEx* getButtonImage( int index, bool large ) 99 { 100 static vcl::DeleteOnDeinit< BitmapEx > gSmallButtonImages[BMP_PLACEHOLDER_SMALL_END - BMP_PLACEHOLDER_SMALL_START] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 101 static vcl::DeleteOnDeinit< BitmapEx > gLargeButtonImages[BMP_PLACEHOLDER_LARGE_END - BMP_PLACEHOLDER_LARGE_START] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 102 103 if( !gSmallButtonImages[0].get() ) 104 { 105 for( sal_uInt16 i = 0; i < (BMP_PLACEHOLDER_SMALL_END-BMP_PLACEHOLDER_SMALL_START); i++ ) 106 { 107 gSmallButtonImages[i].set( new BitmapEx( loadImageResource( BMP_PLACEHOLDER_SMALL_START + i ) ) ); 108 gLargeButtonImages[i].set( new BitmapEx( loadImageResource( BMP_PLACEHOLDER_LARGE_START + i ) ) ); 109 } 110 } 111 112 if( large ) 113 { 114 return gLargeButtonImages[index].get(); 115 } 116 else 117 { 118 return gSmallButtonImages[index].get(); 119 } 120 } 121 122 // -------------------------------------------------------------------- 123 124 const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32; 125 126 class ChangePlaceholderTag : public SmartTag 127 { 128 friend class ImageButtonHdl; 129 public: 130 ChangePlaceholderTag( ViewOverlayManager& rManager, ::sd::View& rView, SdrObject& rPlaceholderObj ); 131 virtual ~ChangePlaceholderTag(); 132 133 /** returns true if the SmartTag handled the event. */ 134 virtual bool MouseButtonDown( const MouseEvent&, SmartHdl& ); 135 136 /** returns true if the SmartTag consumes this event. */ 137 virtual bool KeyInput( const KeyEvent& rKEvt ); 138 139 BitmapEx createOverlayImage( int nHighlight = -1 ); 140 141 protected: 142 virtual void addCustomHandles( SdrHdlList& rHandlerList ); 143 virtual void disposing(); 144 virtual void select(); 145 virtual void deselect(); 146 147 private: 148 ViewOverlayManager& mrManager; 149 SdrObjectWeakRef mxPlaceholderObj; 150 }; 151 152 class ImageButtonHdl : public SmartHdl 153 { 154 public: 155 ImageButtonHdl( const SmartTagReference& xTag, /* sal_uInt16 nSID, const Image& rImage, const Image& rImageMO, */ const Point& rPnt ); 156 virtual ~ImageButtonHdl(); 157 virtual void CreateB2dIAObject(); 158 virtual sal_Bool IsFocusHdl() const; 159 virtual Pointer GetPointer() const; 160 virtual bool isMarkable() const; 161 162 virtual void onMouseEnter(const MouseEvent& rMEvt); 163 virtual void onMouseLeave(); 164 165 int getHighlightId() const { return mnHighlightId; } 166 167 void HideTip(); 168 169 private: 170 rtl::Reference< ChangePlaceholderTag > mxTag; 171 172 int mnHighlightId; 173 Size maImageSize; 174 sal_uLong mnTip; 175 }; 176 177 // -------------------------------------------------------------------- 178 179 ImageButtonHdl::ImageButtonHdl( const SmartTagReference& xTag /*, sal_uInt16 nSID, const Image& rImage, const Image& rImageMO*/, const Point& rPnt ) 180 : SmartHdl( xTag, rPnt ) 181 , mxTag( dynamic_cast< ChangePlaceholderTag* >( xTag.get() ) ) 182 , mnHighlightId( -1 ) 183 , maImageSize( 42, 42 ) 184 , mnTip( 0 ) 185 { 186 } 187 188 // -------------------------------------------------------------------- 189 190 ImageButtonHdl::~ImageButtonHdl() 191 { 192 HideTip(); 193 } 194 195 // -------------------------------------------------------------------- 196 197 void ImageButtonHdl::HideTip() 198 { 199 if( mnTip ) 200 { 201 Help::HideTip( mnTip ); 202 mnTip = 0; 203 } 204 } 205 206 // -------------------------------------------------------------------- 207 208 extern ::rtl::OUString ImplRetrieveLabelFromCommand( const Reference< XFrame >& xFrame, const OUString& aCmdURL ); 209 210 void ImageButtonHdl::onMouseEnter(const MouseEvent& rMEvt) 211 { 212 int nHighlightId = 0; 213 214 if( pHdlList && pHdlList->GetView()) 215 { 216 OutputDevice* pDev = pHdlList->GetView()->GetFirstOutputDevice(); 217 if( pDev == 0 ) 218 pDev = Application::GetDefaultDevice(); 219 220 Point aMDPos( rMEvt.GetPosPixel() ); 221 aMDPos -= pDev->LogicToPixel( GetPos() ); 222 223 nHighlightId += aMDPos.X() > maImageSize.Width() ? 1 : 0; 224 nHighlightId += aMDPos.Y() > maImageSize.Height() ? 2 : 0; 225 226 if( mnHighlightId != nHighlightId ) 227 { 228 HideTip(); 229 230 mnHighlightId = nHighlightId; 231 232 if( pHdlList ) 233 { 234 SdResId aResId( gButtonToolTips[mnHighlightId] ); 235 aResId.SetRT( RSC_STRING ); 236 237 String aHelpText( aResId ); 238 Rectangle aScreenRect( pDev->LogicToPixel( GetPos() ), maImageSize ); 239 mnTip = Help::ShowTip( static_cast< ::Window* >( pHdlList->GetView()->GetFirstOutputDevice() ), aScreenRect, aHelpText, 0 ) ; 240 } 241 Touch(); 242 } 243 } 244 } 245 246 // -------------------------------------------------------------------- 247 248 void ImageButtonHdl::onMouseLeave() 249 { 250 mnHighlightId = -1; 251 HideTip(); 252 Touch(); 253 } 254 255 // -------------------------------------------------------------------- 256 257 void ImageButtonHdl::CreateB2dIAObject() 258 { 259 // first throw away old one 260 GetRidOfIAObject(); 261 262 const Point aTagPos( GetPos() ); 263 basegfx::B2DPoint aPosition( aTagPos.X(), aTagPos.Y() ); 264 265 BitmapEx aBitmapEx( mxTag->createOverlayImage( mnHighlightId ) ); // maImageMO.GetBitmapEx() : maImage.GetBitmapEx() ); 266 maImageSize = aBitmapEx.GetSizePixel(); 267 maImageSize.Width() >>= 1; 268 maImageSize.Height() >>= 1; 269 270 if(pHdlList) 271 { 272 SdrMarkView* pView = pHdlList->GetView(); 273 274 if(pView && !pView->areMarkHandlesHidden()) 275 { 276 SdrPageView* pPageView = pView->GetSdrPageView(); 277 278 if(pPageView) 279 { 280 for(sal_uInt32 b = 0; b < pPageView->PageWindowCount(); b++) 281 { 282 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b); 283 284 SdrPaintWindow& rPaintWindow = rPageWindow.GetPaintWindow(); 285 if(rPaintWindow.OutputToWindow() && rPageWindow.GetOverlayManager() ) 286 { 287 ::sdr::overlay::OverlayObject* pOverlayObject = 0; 288 289 pOverlayObject = new ::sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 ); 290 rPageWindow.GetOverlayManager()->add(*pOverlayObject); 291 maOverlayGroup.append(*pOverlayObject); 292 } 293 } 294 } 295 } 296 } 297 } 298 299 // -------------------------------------------------------------------- 300 301 sal_Bool ImageButtonHdl::IsFocusHdl() const 302 { 303 return false; 304 } 305 306 // -------------------------------------------------------------------- 307 308 bool ImageButtonHdl::isMarkable() const 309 { 310 return false; 311 } 312 313 // -------------------------------------------------------------------- 314 315 Pointer ImageButtonHdl::GetPointer() const 316 { 317 return Pointer( POINTER_ARROW ); 318 } 319 320 // ==================================================================== 321 322 ChangePlaceholderTag::ChangePlaceholderTag( ViewOverlayManager& rManager, ::sd::View& rView, SdrObject& rPlaceholderObj ) 323 : SmartTag( rView ) 324 , mrManager( rManager ) 325 , mxPlaceholderObj( &rPlaceholderObj ) 326 { 327 } 328 329 // -------------------------------------------------------------------- 330 331 ChangePlaceholderTag::~ChangePlaceholderTag() 332 { 333 } 334 335 // -------------------------------------------------------------------- 336 337 /** returns true if the ChangePlaceholderTag handled the event. */ 338 bool ChangePlaceholderTag::MouseButtonDown( const MouseEvent& /*rMEvt*/, SmartHdl& rHdl ) 339 { 340 int nHighlightId = static_cast< ImageButtonHdl& >(rHdl).getHighlightId(); 341 if( nHighlightId >= 0 ) 342 { 343 sal_uInt16 nSID = gButtonSlots[nHighlightId]; 344 345 if( mxPlaceholderObj.get() ) 346 { 347 // mark placeholder if it is not currently marked (or if also others are marked) 348 if( !mrView.IsObjMarked( mxPlaceholderObj.get() ) || (mrView.GetMarkedObjectList().GetMarkCount() != 1) ) 349 { 350 SdrPageView* pPV = mrView.GetSdrPageView(); 351 mrView.UnmarkAllObj(pPV ); 352 mrView.MarkObj(mxPlaceholderObj.get(), pPV, sal_False); 353 } 354 } 355 356 mrView.GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( nSID, SFX_CALLMODE_ASYNCHRON); 357 } 358 return false; 359 } 360 361 // -------------------------------------------------------------------- 362 363 /** returns true if the SmartTag consumes this event. */ 364 bool ChangePlaceholderTag::KeyInput( const KeyEvent& rKEvt ) 365 { 366 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); 367 switch( nCode ) 368 { 369 case KEY_DOWN: 370 case KEY_UP: 371 case KEY_LEFT: 372 case KEY_RIGHT: 373 case KEY_ESCAPE: 374 case KEY_TAB: 375 case KEY_RETURN: 376 case KEY_SPACE: 377 default: 378 return false; 379 } 380 } 381 382 // -------------------------------------------------------------------- 383 384 BitmapEx ChangePlaceholderTag::createOverlayImage( int nHighlight ) 385 { 386 BitmapEx aRet; 387 if( mxPlaceholderObj.is() ) 388 { 389 SdrObject* pPlaceholder = mxPlaceholderObj.get(); 390 SmartTagReference xThis( this ); 391 const Rectangle& rSnapRect = pPlaceholder->GetSnapRect(); 392 const Point aPoint; 393 394 OutputDevice* pDev = mrView.GetFirstOutputDevice(); 395 if( pDev == 0 ) 396 pDev = Application::GetDefaultDevice(); 397 398 Size aShapeSizePix = pDev->LogicToPixel(rSnapRect.GetSize()); 399 long nShapeSizePix = std::min(aShapeSizePix.Width(),aShapeSizePix.Height()); 400 401 bool bLarge = nShapeSizePix > 250; 402 403 Size aSize( getButtonImage( 0, bLarge )->GetSizePixel() ); 404 405 aRet.SetSizePixel( Size( aSize.Width() << 1, aSize.Height() << 1 ) ); 406 407 const Rectangle aRectSrc( Point( 0, 0 ), aSize ); 408 409 aRet = *(getButtonImage((nHighlight == 0) ? 4 : 0, bLarge)); 410 aRet.Expand( aSize.Width(), aSize.Height(), NULL, sal_True ); 411 412 aRet.CopyPixel( Rectangle( Point( aSize.Width(), 0 ), aSize ), aRectSrc, getButtonImage((nHighlight == 1) ? 5 : 1, bLarge) ); 413 aRet.CopyPixel( Rectangle( Point( 0, aSize.Height() ), aSize ), aRectSrc, getButtonImage((nHighlight == 2) ? 6 : 2, bLarge) ); 414 aRet.CopyPixel( Rectangle( Point( aSize.Width(), aSize.Height() ), aSize ), aRectSrc, getButtonImage((nHighlight == 3) ? 7 : 3, bLarge) ); 415 } 416 417 return aRet; 418 } 419 420 void ChangePlaceholderTag::addCustomHandles( SdrHdlList& rHandlerList ) 421 { 422 if( mxPlaceholderObj.is() ) 423 { 424 SdrObject* pPlaceholder = mxPlaceholderObj.get(); 425 SmartTagReference xThis( this ); 426 const Rectangle& rSnapRect = pPlaceholder->GetSnapRect(); 427 const Point aPoint; 428 429 OutputDevice* pDev = mrView.GetFirstOutputDevice(); 430 if( pDev == 0 ) 431 pDev = Application::GetDefaultDevice(); 432 433 Size aShapeSizePix = pDev->LogicToPixel(rSnapRect.GetSize()); 434 long nShapeSizePix = std::min(aShapeSizePix.Width(),aShapeSizePix.Height()); 435 if( 50 > nShapeSizePix ) 436 return; 437 438 bool bLarge = nShapeSizePix > 250; 439 440 Size aButtonSize( pDev->PixelToLogic( getButtonImage(0, bLarge )->GetSizePixel()) ); 441 442 const int nColumns = 2; 443 const int nRows = 2; 444 445 long all_width = nColumns * aButtonSize.Width(); 446 long all_height = nRows * aButtonSize.Height(); 447 448 Point aPos( rSnapRect.Center() ); 449 aPos.X() -= all_width >> 1; 450 aPos.Y() -= all_height >> 1; 451 452 ImageButtonHdl* pHdl = new ImageButtonHdl( xThis, aPoint ); 453 pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM ); 454 pHdl->SetPageView( mrView.GetSdrPageView() ); 455 456 pHdl->SetPos( aPos ); 457 458 rHandlerList.AddHdl( pHdl ); 459 } 460 } 461 462 // -------------------------------------------------------------------- 463 464 void ChangePlaceholderTag::disposing() 465 { 466 SmartTag::disposing(); 467 } 468 469 // -------------------------------------------------------------------- 470 471 void ChangePlaceholderTag::select() 472 { 473 SmartTag::select(); 474 } 475 476 // -------------------------------------------------------------------- 477 478 void ChangePlaceholderTag::deselect() 479 { 480 SmartTag::deselect(); 481 } 482 483 // -------------------------------------------------------------------- 484 485 ViewOverlayManager::ViewOverlayManager( ViewShellBase& rViewShellBase ) 486 : mrBase( rViewShellBase ) 487 , mnUpdateTagsEvent( 0 ) 488 { 489 Link aLink( LINK(this,ViewOverlayManager,EventMultiplexerListener) ); 490 mrBase.GetEventMultiplexer()->AddEventListener(aLink, tools::EventMultiplexerEvent::EID_CURRENT_PAGE 491 | tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED 492 | tools::EventMultiplexerEvent::EID_VIEW_ADDED 493 | tools::EventMultiplexerEvent::EID_BEGIN_TEXT_EDIT 494 | tools::EventMultiplexerEvent::EID_END_TEXT_EDIT ); 495 496 StartListening( *mrBase.GetDocShell() ); 497 } 498 499 // -------------------------------------------------------------------- 500 501 ViewOverlayManager::~ViewOverlayManager() 502 { 503 Link aLink( LINK(this,ViewOverlayManager,EventMultiplexerListener) ); 504 mrBase.GetEventMultiplexer()->RemoveEventListener( aLink ); 505 506 if( mnUpdateTagsEvent ) 507 { 508 Application::RemoveUserEvent( mnUpdateTagsEvent ); 509 mnUpdateTagsEvent = 0; 510 } 511 512 DisposeTags(); 513 } 514 515 // -------------------------------------------------------------------- 516 517 void ViewOverlayManager::Notify(SfxBroadcaster&, const SfxHint& rHint) 518 { 519 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint); 520 if (pSimpleHint != NULL) 521 { 522 if (pSimpleHint->GetId() == SFX_HINT_DOCCHANGED) 523 { 524 UpdateTags(); 525 } 526 } 527 } 528 529 void ViewOverlayManager::onZoomChanged() 530 { 531 if( !maTagVector.empty() ) 532 { 533 UpdateTags(); 534 } 535 } 536 537 void ViewOverlayManager::UpdateTags() 538 { 539 if( !mnUpdateTagsEvent ) 540 mnUpdateTagsEvent = Application::PostUserEvent( LINK( this, ViewOverlayManager, UpdateTagsHdl ) ); 541 } 542 543 IMPL_LINK(ViewOverlayManager,UpdateTagsHdl, void *, EMPTYARG) 544 { 545 OSL_TRACE("ViewOverlayManager::UpdateTagsHdl"); 546 547 mnUpdateTagsEvent = 0; 548 bool bChanges = DisposeTags(); 549 bChanges |= CreateTags(); 550 551 if( bChanges && mrBase.GetDrawView() ) 552 static_cast< ::sd::View* >( mrBase.GetDrawView() )->updateHandles(); 553 return 0; 554 } 555 556 bool ViewOverlayManager::CreateTags() 557 { 558 bool bChanges = false; 559 560 SdPage* pPage = mrBase.GetMainViewShell()->getCurrentPage(); 561 562 if( pPage && !pPage->IsMasterPage() && (pPage->GetPageKind() == PK_STANDARD) ) 563 { 564 const std::list< SdrObject* >& rShapes = pPage->GetPresentationShapeList().getList(); 565 566 for( std::list< SdrObject* >::const_iterator iter( rShapes.begin() ); iter != rShapes.end(); iter++ ) 567 { 568 if( (*iter)->IsEmptyPresObj() && ((*iter)->GetObjIdentifier() == OBJ_OUTLINETEXT) && (mrBase.GetDrawView()->GetTextEditObject() != (*iter)) ) 569 { 570 rtl::Reference< SmartTag > xTag( new ChangePlaceholderTag( *this, *mrBase.GetMainViewShell()->GetView(), *(*iter) ) ); 571 maTagVector.push_back(xTag); 572 bChanges = true; 573 } 574 } 575 } 576 577 return bChanges; 578 } 579 580 // -------------------------------------------------------------------- 581 582 bool ViewOverlayManager::DisposeTags() 583 { 584 if( !maTagVector.empty() ) 585 { 586 ViewTagVector vec; 587 vec.swap( maTagVector ); 588 589 ViewTagVector::iterator iter = vec.begin(); 590 do 591 { 592 (*iter++)->Dispose(); 593 } 594 while( iter != vec.end() ); 595 return true; 596 } 597 598 return false; 599 } 600 601 // -------------------------------------------------------------------- 602 603 IMPL_LINK(ViewOverlayManager,EventMultiplexerListener, 604 tools::EventMultiplexerEvent*,pEvent) 605 { 606 switch (pEvent->meEventId) 607 { 608 case tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED: 609 case tools::EventMultiplexerEvent::EID_VIEW_ADDED: 610 case tools::EventMultiplexerEvent::EID_BEGIN_TEXT_EDIT: 611 case tools::EventMultiplexerEvent::EID_END_TEXT_EDIT: 612 case tools::EventMultiplexerEvent::EID_CURRENT_PAGE: 613 UpdateTags(); 614 break; 615 } 616 return 0; 617 } 618 619 } 620