xref: /trunk/main/sd/source/ui/view/viewoverlaymanager.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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