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