1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: motionpathtag.cxx,v $
12 * This file is part of OpenOffice.org.
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.
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).
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.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sd.hxx"
34 #include <com/sun/star/util/XChangesNotifier.hpp>
36 #include <vcl/help.hxx>
37 #include <vcl/svapp.hxx>
39 #include <sfx2/viewfrm.hxx>
40 #include <sfx2/dispatch.hxx>
42 #include <svx/sdr/overlay/overlaymanager.hxx>
43 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
44 #include <svx/sdr/overlay/overlaybitmapex.hxx>
45 #include <svx/svdpagv.hxx>
46 #include <svx/sdrpagewindow.hxx>
47 #include <svx/sdrpaintwindow.hxx>
48 #include <svx/svddrgmt.hxx>
51 #include "sdresid.hxx"
52 #include "annotations.hrc"
53 #include "annotationmanagerimpl.hxx"
54 #include "annotationwindow.hxx"
55 #include "annotationtag.hxx"
57 #include "ViewShell.hxx"
60 #include "drawdoc.hxx"
62 using ::rtl::OUString
;
63 using namespace ::com::sun::star::uno
;
64 using namespace ::com::sun::star::lang
;
65 //using namespace ::com::sun::star::util;
66 using namespace ::com::sun::star::drawing
;
67 using namespace ::com::sun::star::office
;
68 using namespace ::com::sun::star::geometry
;
73 const sal_uInt32 SMART_TAG_HDL_NUM
= SAL_MAX_UINT32
;
74 static const int DRGPIX
= 2; // Drag MinMove in Pixel
76 // --------------------------------------------------------------------
78 static OUString
getInitials( const OUString
& rName
)
82 const sal_Unicode
* pStr
= rName
.getStr();
83 sal_Int32 nLength
= rName
.getLength();
88 while( nLength
&& (*pStr
<= ' ') )
96 sInitials
+= OUString( *pStr
);
100 // skip letters until whitespace
101 while( nLength
&& (*pStr
> ' ') )
110 // --------------------------------------------------------------------
112 // --------------------------------------------------------------------
114 class AnnotationDragMove
: public SdrDragMove
117 AnnotationDragMove(SdrDragView
& rNewView
, const rtl::Reference
<AnnotationTag
>& xTag
);
118 virtual bool BeginSdrDrag();
119 virtual bool EndSdrDrag(bool bCopy
);
120 virtual void MoveSdrDrag(const Point
& rNoSnapPnt
);
121 virtual void CancelSdrDrag();
124 rtl::Reference
<AnnotationTag
> mxTag
;
128 AnnotationDragMove::AnnotationDragMove(SdrDragView
& rNewView
, const rtl::Reference
<AnnotationTag
>& xTag
)
129 : SdrDragMove(rNewView
)
134 bool AnnotationDragMove::BeginSdrDrag()
136 DragStat().Ref1()=GetDragHdl()->GetPos();
137 DragStat().SetShown(!DragStat().IsShown());
139 maOrigin
= GetDragHdl()->GetPos();
140 DragStat().SetActionRect(Rectangle(maOrigin
,maOrigin
));
145 void AnnotationDragMove::MoveSdrDrag(const Point
& rNoSnapPnt
)
147 Point
aPnt(rNoSnapPnt
);
149 if (DragStat().CheckMinMoved(rNoSnapPnt
))
151 if (aPnt
!=DragStat().GetNow())
154 DragStat().NextMove(aPnt
);
155 GetDragHdl()->SetPos( maOrigin
+ Point( DragStat().GetDX(), DragStat().GetDY() ) );
157 DragStat().SetActionRect(Rectangle(aPnt
,aPnt
));
162 bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
166 mxTag
->Move( DragStat().GetDX(), DragStat().GetDY() );
170 void AnnotationDragMove::CancelSdrDrag()
175 // --------------------------------------------------------------------
177 class AnnotationHdl
: public SmartHdl
180 AnnotationHdl( const SmartTagReference
& xTag
, const Reference
< XAnnotation
>& xAnnotation
, const Point
& rPnt
);
181 virtual ~AnnotationHdl();
182 virtual void CreateB2dIAObject();
183 virtual BOOL
IsFocusHdl() const;
184 virtual Pointer
GetSdrDragPointer() const;
185 virtual bool isMarkable() const;
189 Reference
< XAnnotation
> mxAnnotation
;
190 rtl::Reference
< AnnotationTag
> mxTag
;
193 // --------------------------------------------------------------------
195 AnnotationHdl::AnnotationHdl( const SmartTagReference
& xTag
, const Reference
< XAnnotation
>& xAnnotation
, const Point
& rPnt
)
196 : SmartHdl( xTag
, rPnt
)
197 , mxAnnotation( xAnnotation
)
198 , mxTag( dynamic_cast< AnnotationTag
* >( xTag
.get() ) )
202 // --------------------------------------------------------------------
204 AnnotationHdl::~AnnotationHdl()
208 // --------------------------------------------------------------------
210 void AnnotationHdl::CreateB2dIAObject()
212 // first throw away old one
215 if( mxAnnotation
.is() )
217 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
219 const Point
aTagPos( GetPos() );
220 basegfx::B2DPoint
aPosition( aTagPos
.X(), aTagPos
.Y() );
222 const bool bFocused
= IsFocusHdl() && pHdlList
&& (pHdlList
->GetFocusHdl() == this);
224 BitmapEx
aBitmapEx( mxTag
->CreateAnnotationBitmap(mxTag
->isSelected()) );
227 aBitmapEx2
= mxTag
->CreateAnnotationBitmap(!mxTag
->isSelected() );
231 SdrMarkView
* pView
= pHdlList
->GetView();
233 if(pView
&& !pView
->areMarkHandlesHidden())
235 SdrPageView
* pPageView
= pView
->GetSdrPageView();
239 for(sal_uInt32 b
= 0; b
< pPageView
->PageWindowCount(); b
++)
241 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
242 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
244 SdrPaintWindow
& rPaintWindow
= rPageWindow
.GetPaintWindow();
245 if(rPaintWindow
.OutputToWindow() && rPageWindow
.GetOverlayManager() )
247 ::sdr::overlay::OverlayObject
* pOverlayObject
= 0;
249 // animate focused handles
252 const sal_uInt32 nBlinkTime
= sal::static_int_cast
<sal_uInt32
>(rStyleSettings
.GetCursorBlinkTime());
254 pOverlayObject
= new ::sdr::overlay::OverlayAnimatedBitmapEx(aPosition
, aBitmapEx
, aBitmapEx2
, nBlinkTime
, 0, 0, 0, 0 );
256 (UINT16)(aBitmapEx.GetSizePixel().Width() - 1) >> 1,
257 (UINT16)(aBitmapEx.GetSizePixel().Height() - 1) >> 1,
258 (UINT16)(aBitmapEx2.GetSizePixel().Width() - 1) >> 1,
259 (UINT16)(aBitmapEx2.GetSizePixel().Height() - 1) >> 1);
264 pOverlayObject
= new ::sdr::overlay::OverlayBitmapEx( aPosition
, aBitmapEx
, 0, 0 );
267 rPageWindow
.GetOverlayManager()->add(*pOverlayObject
);
268 maOverlayGroup
.append(*pOverlayObject
);
277 // --------------------------------------------------------------------
279 BOOL
AnnotationHdl::IsFocusHdl() const
284 // --------------------------------------------------------------------
286 bool AnnotationHdl::isMarkable() const
291 // --------------------------------------------------------------------
293 Pointer
AnnotationHdl::GetSdrDragPointer() const
295 PointerStyle eStyle
= POINTER_NOTALLOWED
;
298 if( mxTag
->isSelected() )
300 eStyle
= POINTER_MOVE
;
304 eStyle
= POINTER_ARROW
;
308 return Pointer( eStyle
);
311 // ====================================================================
313 AnnotationTag::AnnotationTag( AnnotationManagerImpl
& rManager
, ::sd::View
& rView
, const Reference
< XAnnotation
>& xAnnotation
, Color
& rColor
, int nIndex
, const Font
& rFont
)
315 , mrManager( rManager
)
316 , mxAnnotation( xAnnotation
)
320 , mnClosePopupEvent( 0 )
321 , mpListenWindow( 0 )
325 // --------------------------------------------------------------------
327 AnnotationTag::~AnnotationTag()
329 DBG_ASSERT( !mxAnnotation
.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
333 // --------------------------------------------------------------------
335 /** returns true if the AnnotationTag handled the event. */
336 bool AnnotationTag::MouseButtonDown( const MouseEvent
& rMEvt
, SmartHdl
& /*rHdl*/ )
338 if( !mxAnnotation
.is() )
344 SmartTagReference
xTag( this );
345 mrView
.getSmartTags().select( xTag
);
349 if( rMEvt.IsLeft() && (rMEvt.GetClicks() == 2) )
355 if( rMEvt
.IsLeft() && !rMEvt
.IsRight() )
357 Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
360 maMouseDownPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
363 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
365 mpListenWindow
= pWindow
;
366 mpListenWindow
->AddEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
375 // --------------------------------------------------------------------
377 /** returns true if the SmartTag consumes this event. */
378 bool AnnotationTag::KeyInput( const KeyEvent
& rKEvt
)
380 if( !mxAnnotation
.is() )
383 USHORT nCode
= rKEvt
.GetKeyCode().GetCode();
387 mrManager
.DeleteAnnotation( mxAnnotation
);
394 return OnMove( rKEvt
);
398 SmartTagReference
xThis( this );
399 mrView
.getSmartTags().deselect();
404 mrManager
.SelectNextAnnotation(!rKEvt
.GetKeyCode().IsShift());
417 /** returns true if the SmartTag consumes this event. */
418 bool AnnotationTag::RequestHelp( const HelpEvent
& /*rHEvt*/ )
421 ::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
422 if( mxAnnotation.is() && pWindow )
424 OUString aHelpText( mrManager.GetHelpText( mxAnnotation ) );
426 RealPoint2D aPosition( mxAnnotation->getPosition() );
427 Point aPos( pWindow->LogicToPixel( Point( static_cast<long>(aPosition.X * 100.0), static_cast<long>(aPosition.Y * 100.0) ) ) );
429 Rectangle aRect( aPos, maSize );
431 if (Help::IsBalloonHelpEnabled())
432 Help::ShowBalloon( pWindow, aPos, aRect, aHelpText);
433 else if (Help::IsQuickHelpEnabled())
434 Help::ShowQuickHelp( pWindow, aRect, aHelpText);
442 /** returns true if the SmartTag consumes this event. */
443 bool AnnotationTag::Command( const CommandEvent
& rCEvt
)
445 if ( rCEvt
.GetCommand() == COMMAND_CONTEXTMENU
)
447 ::Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
450 Rectangle
aContextRect(rCEvt
.GetMousePosPixel(),Size(1,1));
451 mrManager
.ExecuteAnnotationContextMenu( mxAnnotation
, pWindow
, aContextRect
);
459 void AnnotationTag::Move( int nDX
, int nDY
)
461 if( mxAnnotation
.is() )
463 if( mrManager
.GetDoc()->IsUndoEnabled() )
464 mrManager
.GetDoc()->BegUndo( String( SdResId( STR_ANNOTATION_UNDO_MOVE
) ) );
466 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
467 aPosition
.X
+= (double)nDX
/ 100.0;
468 aPosition
.Y
+= (double)nDY
/ 100.0;
469 mxAnnotation
->setPosition( aPosition
);
471 if( mrManager
.GetDoc()->IsUndoEnabled() )
472 mrManager
.GetDoc()->EndUndo();
474 mrView
.updateHandles();
478 bool AnnotationTag::OnMove( const KeyEvent
& rKEvt
)
483 switch( rKEvt
.GetKeyCode().GetCode() )
485 case KEY_UP
: nY
= -1; break;
486 case KEY_DOWN
: nY
= 1; break;
487 case KEY_LEFT
: nX
= -1; break;
488 case KEY_RIGHT
: nX
= 1; break;
492 if(rKEvt
.GetKeyCode().IsMod2())
494 OutputDevice
* pOut
= mrView
.GetViewShell()->GetActiveWindow();
495 Size aLogicSizeOnePixel
= (pOut
) ? pOut
->PixelToLogic(Size(1,1)) : Size(100, 100);
496 nX
*= aLogicSizeOnePixel
.Width();
497 nY
*= aLogicSizeOnePixel
.Height();
501 // old, fixed move distance
508 // move the annotation
515 // --------------------------------------------------------------------
517 void AnnotationTag::CheckPossibilities()
521 // --------------------------------------------------------------------
523 ULONG
AnnotationTag::GetMarkablePointCount() const
528 // --------------------------------------------------------------------
530 ULONG
AnnotationTag::GetMarkedPointCount() const
535 // --------------------------------------------------------------------
537 BOOL
AnnotationTag::MarkPoint(SdrHdl
& /*rHdl*/, BOOL
/*bUnmark*/ )
543 // --------------------------------------------------------------------
545 BOOL
AnnotationTag::MarkPoints(const Rectangle
* /*pRect*/, BOOL
/*bUnmark*/ )
551 // --------------------------------------------------------------------
553 bool AnnotationTag::getContext( SdrViewContext
& /*rContext*/ )
558 // --------------------------------------------------------------------
560 void AnnotationTag::addCustomHandles( SdrHdlList
& rHandlerList
)
562 if( mxAnnotation
.is() )
564 SmartTagReference
xThis( this );
566 AnnotationHdl
* pHdl
= new AnnotationHdl( xThis
, mxAnnotation
, aPoint
);
567 pHdl
->SetObjHdlNum( SMART_TAG_HDL_NUM
);
568 pHdl
->SetPageView( mrView
.GetSdrPageView() );
570 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
571 Point
aBasePos( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) );
572 pHdl
->SetPos( aBasePos
);
574 rHandlerList
.AddHdl( pHdl
);
578 // --------------------------------------------------------------------
580 void AnnotationTag::disposing()
584 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
587 if( mnClosePopupEvent
)
589 Application::RemoveUserEvent( mnClosePopupEvent
);
590 mnClosePopupEvent
= 0;
593 mxAnnotation
.clear();
595 SmartTag::disposing();
598 // --------------------------------------------------------------------
600 void AnnotationTag::select()
604 mrManager
.onTagSelected( *this );
606 Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
609 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
610 Point
aPos( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) );
612 Rectangle
aVisRect( aPos
, pWindow
->PixelToLogic(maSize
) );
613 mrView
.MakeVisible(aVisRect
, *pWindow
);
617 // --------------------------------------------------------------------
619 void AnnotationTag::deselect()
621 SmartTag::deselect();
625 mrManager
.onTagDeselected( *this );
628 // --------------------------------------------------------------------
630 BitmapEx
AnnotationTag::CreateAnnotationBitmap( bool bSelected
)
634 OUString
sAuthor( getInitials( mxAnnotation
->getAuthor() ) );
635 sAuthor
+= OUString( sal_Unicode( ' ' ) );
636 sAuthor
+= OUString::valueOf( (sal_Int32
)mnIndex
);
638 aVDev
.SetFont( mrFont
);
640 const int BORDER_X
= 4; // pixels
641 const int BORDER_Y
= 4; // pixels
643 maSize
= Size( aVDev
.GetTextWidth( sAuthor
) + 2*BORDER_X
, aVDev
.GetTextHeight() + 2*BORDER_Y
);
644 aVDev
.SetOutputSizePixel( maSize
, FALSE
);
646 Color
aBorderColor( maColor
);
650 aBorderColor
.Invert();
654 if( maColor
.IsDark() )
656 aBorderColor
.IncreaseLuminance( 32 );
660 aBorderColor
.DecreaseLuminance( 32 );
665 Rectangle
aBorderRect( aPos
, maSize
);
666 aVDev
.SetLineColor(aBorderColor
);
667 aVDev
.SetFillColor(maColor
);
668 aVDev
.DrawRect( aBorderRect
);
670 aVDev
.SetTextColor( maColor
.IsDark() ? COL_WHITE
: COL_BLACK
);
671 aVDev
.DrawText( Point( BORDER_X
, BORDER_Y
), sAuthor
);
673 return aVDev
.GetBitmapEx( aPos
, maSize
);
676 void AnnotationTag::OpenPopup( bool bEdit
)
678 if( !mxAnnotation
.is() )
681 if( !mpAnnotationWindow
.get() )
683 ::Window
* pWindow
= dynamic_cast< ::Window
* >( getView().GetFirstOutputDevice() );
686 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
687 Point
aPos( pWindow
->OutputToScreenPixel( pWindow
->LogicToPixel( Point( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) ) ) ) );
689 aPos
.X() += 4; // magic!
692 Rectangle
aRect( aPos
, maSize
);
694 mpAnnotationWindow
.reset( new AnnotationWindow( mrManager
, mrView
.GetDocSh(), pWindow
->GetWindow(WINDOW_FRAME
) ) );
695 mpAnnotationWindow
->InitControls();
696 mpAnnotationWindow
->setAnnotation(mxAnnotation
);
698 USHORT nArrangeIndex
= 0;
699 Point
aPopupPos( FloatingWindow::CalcFloatingPosition( mpAnnotationWindow
.get(), aRect
, FLOATWIN_POPUPMODE_RIGHT
, nArrangeIndex
) );
700 Size
aPopupSize( 320, 240 );
702 mpAnnotationWindow
->SetPosSizePixel( aPopupPos
, aPopupSize
);
703 mpAnnotationWindow
->DoResize();
705 mpAnnotationWindow
->Show();
706 mpAnnotationWindow
->GrabFocus();
707 mpAnnotationWindow
->AddEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
711 if( bEdit
&& mpAnnotationWindow
.get() )
712 mpAnnotationWindow
->StartEdit();
715 void AnnotationTag::ClosePopup()
717 if( mpAnnotationWindow
.get() )
719 mpAnnotationWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
720 mpAnnotationWindow
->Deactivate();
721 mpAnnotationWindow
.reset();
725 IMPL_LINK(AnnotationTag
, WindowEventHandler
, VclWindowEvent
*, pEvent
)
729 ::Window
* pWindow
= pEvent
->GetWindow();
733 if( pWindow
== mpAnnotationWindow
.get() )
735 if( pEvent
->GetId() == VCLEVENT_WINDOW_DEACTIVATE
)
737 if( mnClosePopupEvent
)
738 Application::RemoveUserEvent( mnClosePopupEvent
);
740 mnClosePopupEvent
= Application::PostUserEvent( LINK( this, AnnotationTag
, ClosePopupHdl
) );
743 else if( pWindow
== mpListenWindow
)
745 switch( pEvent
->GetId() )
747 case VCLEVENT_WINDOW_MOUSEBUTTONUP
:
749 // if we stop pressing the button without a mouse move we open the popup
750 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
752 if( mpAnnotationWindow
.get() == 0 )
756 case VCLEVENT_WINDOW_MOUSEMOVE
:
758 // if we move the mouse after a button down we wan't to start draging
759 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
762 SdrHdl
* pHdl
= mrView
.PickHandle(maMouseDownPos
);
766 const USHORT nDrgLog
= (USHORT
)pWindow
->PixelToLogic(Size(DRGPIX
,0)).Width();
768 rtl::Reference
< AnnotationTag
> xTag( this );
770 SdrDragMethod
* pDragMethod
= new AnnotationDragMove( mrView
, xTag
);
771 mrView
.BegDragObj(maMouseDownPos
, NULL
, pHdl
, nDrgLog
, pDragMethod
);
775 case VCLEVENT_OBJECT_DYING
:
785 IMPL_LINK( AnnotationTag
, ClosePopupHdl
, void *, EMPTYARG
)
787 mnClosePopupEvent
= 0;
792 } // end of namespace sd