1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/util/XChangesNotifier.hpp>
23 #include <vcl/help.hxx>
24 #include <vcl/svapp.hxx>
26 #include <sfx2/viewfrm.hxx>
27 #include <sfx2/dispatch.hxx>
29 #include <svx/sdr/overlay/overlaymanager.hxx>
30 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
31 #include <svx/sdr/overlay/overlaybitmapex.hxx>
32 #include <svx/svdpagv.hxx>
33 #include <svx/sdrpagewindow.hxx>
34 #include <svx/sdrpaintwindow.hxx>
35 #include <svx/svddrgmt.hxx>
38 #include "sdresid.hxx"
39 #include "annotations.hrc"
40 #include "annotationmanagerimpl.hxx"
41 #include "annotationwindow.hxx"
42 #include "annotationtag.hxx"
44 #include "ViewShell.hxx"
47 #include "drawdoc.hxx"
49 using namespace ::com::sun::star::uno
;
50 using namespace ::com::sun::star::lang
;
51 using namespace ::com::sun::star::drawing
;
52 using namespace ::com::sun::star::office
;
53 using namespace ::com::sun::star::geometry
;
58 const sal_uInt32 SMART_TAG_HDL_NUM
= SAL_MAX_UINT32
;
59 static const int DRGPIX
= 2; // Drag MinMove in Pixel
61 // --------------------------------------------------------------------
63 static OUString
getInitials( const OUString
& rName
)
67 const sal_Unicode
* pStr
= rName
.getStr();
68 sal_Int32 nLength
= rName
.getLength();
73 while( nLength
&& (*pStr
<= ' ') )
81 sInitials
+= OUString( *pStr
);
85 // skip letters until whitespace
86 while( nLength
&& (*pStr
> ' ') )
95 // --------------------------------------------------------------------
97 // --------------------------------------------------------------------
99 class AnnotationDragMove
: public SdrDragMove
102 AnnotationDragMove(SdrDragView
& rNewView
, const rtl::Reference
<AnnotationTag
>& xTag
);
103 virtual bool BeginSdrDrag();
104 virtual bool EndSdrDrag(bool bCopy
);
105 virtual void MoveSdrDrag(const Point
& rNoSnapPnt
);
106 virtual void CancelSdrDrag();
109 rtl::Reference
<AnnotationTag
> mxTag
;
113 AnnotationDragMove::AnnotationDragMove(SdrDragView
& rNewView
, const rtl::Reference
<AnnotationTag
>& xTag
)
114 : SdrDragMove(rNewView
)
119 bool AnnotationDragMove::BeginSdrDrag()
121 DragStat().Ref1()=GetDragHdl()->GetPos();
122 DragStat().SetShown(!DragStat().IsShown());
124 maOrigin
= GetDragHdl()->GetPos();
125 DragStat().SetActionRect(Rectangle(maOrigin
,maOrigin
));
130 void AnnotationDragMove::MoveSdrDrag(const Point
& rNoSnapPnt
)
132 Point
aPnt(rNoSnapPnt
);
134 if (DragStat().CheckMinMoved(rNoSnapPnt
))
136 if (aPnt
!=DragStat().GetNow())
139 DragStat().NextMove(aPnt
);
140 GetDragHdl()->SetPos( maOrigin
+ Point( DragStat().GetDX(), DragStat().GetDY() ) );
142 DragStat().SetActionRect(Rectangle(aPnt
,aPnt
));
147 bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
151 mxTag
->Move( DragStat().GetDX(), DragStat().GetDY() );
155 void AnnotationDragMove::CancelSdrDrag()
160 // --------------------------------------------------------------------
162 class AnnotationHdl
: public SmartHdl
165 AnnotationHdl( const SmartTagReference
& xTag
, const Reference
< XAnnotation
>& xAnnotation
, const Point
& rPnt
);
166 virtual ~AnnotationHdl();
167 virtual void CreateB2dIAObject();
168 virtual sal_Bool
IsFocusHdl() const;
169 virtual Pointer
GetSdrDragPointer() const;
170 virtual bool isMarkable() const;
174 Reference
< XAnnotation
> mxAnnotation
;
175 rtl::Reference
< AnnotationTag
> mxTag
;
178 // --------------------------------------------------------------------
180 AnnotationHdl::AnnotationHdl( const SmartTagReference
& xTag
, const Reference
< XAnnotation
>& xAnnotation
, const Point
& rPnt
)
181 : SmartHdl( xTag
, rPnt
)
182 , mxAnnotation( xAnnotation
)
183 , mxTag( dynamic_cast< AnnotationTag
* >( xTag
.get() ) )
187 // --------------------------------------------------------------------
189 AnnotationHdl::~AnnotationHdl()
193 // --------------------------------------------------------------------
195 void AnnotationHdl::CreateB2dIAObject()
197 // first throw away old one
200 if( mxAnnotation
.is() )
202 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
204 const Point
aTagPos( GetPos() );
205 basegfx::B2DPoint
aPosition( aTagPos
.X(), aTagPos
.Y() );
207 const bool bFocused
= IsFocusHdl() && pHdlList
&& (pHdlList
->GetFocusHdl() == this);
209 BitmapEx
aBitmapEx( mxTag
->CreateAnnotationBitmap(mxTag
->isSelected()) );
212 aBitmapEx2
= mxTag
->CreateAnnotationBitmap(!mxTag
->isSelected() );
216 SdrMarkView
* pView
= pHdlList
->GetView();
218 if(pView
&& !pView
->areMarkHandlesHidden())
220 SdrPageView
* pPageView
= pView
->GetSdrPageView();
224 for(sal_uInt32 b
= 0; b
< pPageView
->PageWindowCount(); b
++)
226 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
227 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
229 SdrPaintWindow
& rPaintWindow
= rPageWindow
.GetPaintWindow();
230 rtl::Reference
< ::sdr::overlay::OverlayManager
> xManager
= rPageWindow
.GetOverlayManager();
231 if(rPaintWindow
.OutputToWindow() && xManager
.is() )
233 ::sdr::overlay::OverlayObject
* pOverlayObject
= 0;
235 // animate focused handles
238 const sal_uInt32 nBlinkTime
= sal::static_int_cast
<sal_uInt32
>(rStyleSettings
.GetCursorBlinkTime());
240 pOverlayObject
= new ::sdr::overlay::OverlayAnimatedBitmapEx(aPosition
, aBitmapEx
, aBitmapEx2
, nBlinkTime
, 0, 0, 0, 0 );
244 pOverlayObject
= new ::sdr::overlay::OverlayBitmapEx( aPosition
, aBitmapEx
, 0, 0 );
247 xManager
->add(*pOverlayObject
);
248 maOverlayGroup
.append(*pOverlayObject
);
257 // --------------------------------------------------------------------
259 sal_Bool
AnnotationHdl::IsFocusHdl() const
264 // --------------------------------------------------------------------
266 bool AnnotationHdl::isMarkable() const
271 // --------------------------------------------------------------------
273 Pointer
AnnotationHdl::GetSdrDragPointer() const
275 PointerStyle eStyle
= POINTER_NOTALLOWED
;
278 if( mxTag
->isSelected() )
280 eStyle
= POINTER_MOVE
;
284 eStyle
= POINTER_ARROW
;
288 return Pointer( eStyle
);
291 // ====================================================================
293 AnnotationTag::AnnotationTag( AnnotationManagerImpl
& rManager
, ::sd::View
& rView
, const Reference
< XAnnotation
>& xAnnotation
, Color
& rColor
, int nIndex
, const Font
& rFont
)
295 , mrManager( rManager
)
296 , mxAnnotation( xAnnotation
)
300 , mnClosePopupEvent( 0 )
301 , mpListenWindow( 0 )
305 // --------------------------------------------------------------------
307 AnnotationTag::~AnnotationTag()
309 DBG_ASSERT( !mxAnnotation
.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
313 // --------------------------------------------------------------------
315 /** returns true if the AnnotationTag handled the event. */
316 bool AnnotationTag::MouseButtonDown( const MouseEvent
& rMEvt
, SmartHdl
& /*rHdl*/ )
318 if( !mxAnnotation
.is() )
324 SmartTagReference
xTag( this );
325 mrView
.getSmartTags().select( xTag
);
329 if( rMEvt
.IsLeft() && !rMEvt
.IsRight() )
331 Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
334 maMouseDownPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
337 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
339 mpListenWindow
= pWindow
;
340 mpListenWindow
->AddEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
349 // --------------------------------------------------------------------
351 /** returns true if the SmartTag consumes this event. */
352 bool AnnotationTag::KeyInput( const KeyEvent
& rKEvt
)
354 if( !mxAnnotation
.is() )
357 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
361 mrManager
.DeleteAnnotation( mxAnnotation
);
368 return OnMove( rKEvt
);
372 SmartTagReference
xThis( this );
373 mrView
.getSmartTags().deselect();
378 mrManager
.SelectNextAnnotation(!rKEvt
.GetKeyCode().IsShift());
391 /** returns true if the SmartTag consumes this event. */
392 bool AnnotationTag::RequestHelp( const HelpEvent
& /*rHEvt*/ )
398 /** returns true if the SmartTag consumes this event. */
399 bool AnnotationTag::Command( const CommandEvent
& rCEvt
)
401 if ( rCEvt
.GetCommand() == COMMAND_CONTEXTMENU
)
403 ::Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
406 Rectangle
aContextRect(rCEvt
.GetMousePosPixel(),Size(1,1));
407 mrManager
.ExecuteAnnotationContextMenu( mxAnnotation
, pWindow
, aContextRect
);
415 void AnnotationTag::Move( int nDX
, int nDY
)
417 if( mxAnnotation
.is() )
419 if( mrManager
.GetDoc()->IsUndoEnabled() )
420 mrManager
.GetDoc()->BegUndo( String( SdResId( STR_ANNOTATION_UNDO_MOVE
) ) );
422 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
423 aPosition
.X
+= (double)nDX
/ 100.0;
424 aPosition
.Y
+= (double)nDY
/ 100.0;
425 mxAnnotation
->setPosition( aPosition
);
427 if( mrManager
.GetDoc()->IsUndoEnabled() )
428 mrManager
.GetDoc()->EndUndo();
430 mrView
.updateHandles();
434 bool AnnotationTag::OnMove( const KeyEvent
& rKEvt
)
439 switch( rKEvt
.GetKeyCode().GetCode() )
441 case KEY_UP
: nY
= -1; break;
442 case KEY_DOWN
: nY
= 1; break;
443 case KEY_LEFT
: nX
= -1; break;
444 case KEY_RIGHT
: nX
= 1; break;
448 if(rKEvt
.GetKeyCode().IsMod2())
450 OutputDevice
* pOut
= mrView
.GetViewShell()->GetActiveWindow();
451 Size aLogicSizeOnePixel
= (pOut
) ? pOut
->PixelToLogic(Size(1,1)) : Size(100, 100);
452 nX
*= aLogicSizeOnePixel
.Width();
453 nY
*= aLogicSizeOnePixel
.Height();
457 // old, fixed move distance
464 // move the annotation
471 // --------------------------------------------------------------------
473 void AnnotationTag::CheckPossibilities()
477 // --------------------------------------------------------------------
479 sal_uLong
AnnotationTag::GetMarkablePointCount() const
484 // --------------------------------------------------------------------
486 sal_uLong
AnnotationTag::GetMarkedPointCount() const
491 // --------------------------------------------------------------------
493 sal_Bool
AnnotationTag::MarkPoint(SdrHdl
& /*rHdl*/, sal_Bool
/*bUnmark*/ )
495 sal_Bool bRet
=sal_False
;
499 // --------------------------------------------------------------------
501 sal_Bool
AnnotationTag::MarkPoints(const Rectangle
* /*pRect*/, sal_Bool
/*bUnmark*/ )
503 sal_Bool bChgd
=sal_False
;
507 // --------------------------------------------------------------------
509 bool AnnotationTag::getContext( SdrViewContext
& /*rContext*/ )
514 // --------------------------------------------------------------------
516 void AnnotationTag::addCustomHandles( SdrHdlList
& rHandlerList
)
518 if( mxAnnotation
.is() )
520 SmartTagReference
xThis( this );
522 AnnotationHdl
* pHdl
= new AnnotationHdl( xThis
, mxAnnotation
, aPoint
);
523 pHdl
->SetObjHdlNum( SMART_TAG_HDL_NUM
);
524 pHdl
->SetPageView( mrView
.GetSdrPageView() );
526 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
527 Point
aBasePos( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) );
528 pHdl
->SetPos( aBasePos
);
530 rHandlerList
.AddHdl( pHdl
);
534 // --------------------------------------------------------------------
536 void AnnotationTag::disposing()
540 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
543 if( mnClosePopupEvent
)
545 Application::RemoveUserEvent( mnClosePopupEvent
);
546 mnClosePopupEvent
= 0;
549 mxAnnotation
.clear();
551 SmartTag::disposing();
554 // --------------------------------------------------------------------
556 void AnnotationTag::select()
560 mrManager
.onTagSelected( *this );
562 Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
565 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
566 Point
aPos( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) );
568 Rectangle
aVisRect( aPos
, pWindow
->PixelToLogic(maSize
) );
569 mrView
.MakeVisible(aVisRect
, *pWindow
);
573 // --------------------------------------------------------------------
575 void AnnotationTag::deselect()
577 SmartTag::deselect();
581 mrManager
.onTagDeselected( *this );
584 // --------------------------------------------------------------------
586 BitmapEx
AnnotationTag::CreateAnnotationBitmap( bool bSelected
)
590 OUString
sAuthor( getInitials( mxAnnotation
->getAuthor() ) );
591 sAuthor
+= OUString( sal_Unicode( ' ' ) );
592 sAuthor
+= OUString::valueOf( (sal_Int32
)mnIndex
);
594 aVDev
.SetFont( mrFont
);
596 const int BORDER_X
= 4; // pixels
597 const int BORDER_Y
= 4; // pixels
599 maSize
= Size( aVDev
.GetTextWidth( sAuthor
) + 2*BORDER_X
, aVDev
.GetTextHeight() + 2*BORDER_Y
);
600 aVDev
.SetOutputSizePixel( maSize
, sal_False
);
602 Color
aBorderColor( maColor
);
606 aBorderColor
.Invert();
610 if( maColor
.IsDark() )
612 aBorderColor
.IncreaseLuminance( 32 );
616 aBorderColor
.DecreaseLuminance( 32 );
621 Rectangle
aBorderRect( aPos
, maSize
);
622 aVDev
.SetLineColor(aBorderColor
);
623 aVDev
.SetFillColor(maColor
);
624 aVDev
.DrawRect( aBorderRect
);
626 aVDev
.SetTextColor( maColor
.IsDark() ? COL_WHITE
: COL_BLACK
);
627 aVDev
.DrawText( Point( BORDER_X
, BORDER_Y
), sAuthor
);
629 return aVDev
.GetBitmapEx( aPos
, maSize
);
632 void AnnotationTag::OpenPopup( bool bEdit
)
634 if( !mxAnnotation
.is() )
637 if( !mpAnnotationWindow
.get() )
639 ::Window
* pWindow
= dynamic_cast< ::Window
* >( getView().GetFirstOutputDevice() );
642 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
643 Point
aPos( pWindow
->OutputToScreenPixel( pWindow
->LogicToPixel( Point( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) ) ) ) );
645 aPos
.X() += 4; // magic!
648 Rectangle
aRect( aPos
, maSize
);
650 mpAnnotationWindow
.reset( new AnnotationWindow( mrManager
, mrView
.GetDocSh(), pWindow
->GetWindow(WINDOW_FRAME
) ) );
651 mpAnnotationWindow
->InitControls();
652 mpAnnotationWindow
->setAnnotation(mxAnnotation
);
654 sal_uInt16 nArrangeIndex
= 0;
655 Point
aPopupPos( FloatingWindow::CalcFloatingPosition( mpAnnotationWindow
.get(), aRect
, FLOATWIN_POPUPMODE_RIGHT
, nArrangeIndex
) );
656 Size
aPopupSize( 320, 240 );
658 mpAnnotationWindow
->SetPosSizePixel( aPopupPos
, aPopupSize
);
659 mpAnnotationWindow
->DoResize();
661 mpAnnotationWindow
->Show();
662 mpAnnotationWindow
->GrabFocus();
663 mpAnnotationWindow
->AddEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
667 if( bEdit
&& mpAnnotationWindow
.get() )
668 mpAnnotationWindow
->StartEdit();
671 void AnnotationTag::ClosePopup()
673 if( mpAnnotationWindow
.get() )
675 mpAnnotationWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
676 mpAnnotationWindow
->Deactivate();
677 mpAnnotationWindow
.reset();
681 IMPL_LINK(AnnotationTag
, WindowEventHandler
, VclWindowEvent
*, pEvent
)
685 ::Window
* pWindow
= pEvent
->GetWindow();
689 if( pWindow
== mpAnnotationWindow
.get() )
691 if( pEvent
->GetId() == VCLEVENT_WINDOW_DEACTIVATE
)
693 if( mnClosePopupEvent
)
694 Application::RemoveUserEvent( mnClosePopupEvent
);
696 mnClosePopupEvent
= Application::PostUserEvent( LINK( this, AnnotationTag
, ClosePopupHdl
) );
699 else if( pWindow
== mpListenWindow
)
701 switch( pEvent
->GetId() )
703 case VCLEVENT_WINDOW_MOUSEBUTTONUP
:
705 // if we stop pressing the button without a mouse move we open the popup
706 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
708 if( mpAnnotationWindow
.get() == 0 )
712 case VCLEVENT_WINDOW_MOUSEMOVE
:
714 // if we move the mouse after a button down we wan't to start draging
715 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
718 SdrHdl
* pHdl
= mrView
.PickHandle(maMouseDownPos
);
722 const sal_uInt16 nDrgLog
= (sal_uInt16
)pWindow
->PixelToLogic(Size(DRGPIX
,0)).Width();
724 rtl::Reference
< AnnotationTag
> xTag( this );
726 SdrDragMethod
* pDragMethod
= new AnnotationDragMove( mrView
, xTag
);
727 mrView
.BegDragObj(maMouseDownPos
, NULL
, pHdl
, nDrgLog
, pDragMethod
);
731 case VCLEVENT_OBJECT_DYING
:
741 IMPL_LINK_NOARG(AnnotationTag
, ClosePopupHdl
)
743 mnClosePopupEvent
= 0;
748 } // end of namespace sd
750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */