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