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 .
20 #include <com/sun/star/util/XChangesNotifier.hpp>
22 #include <vcl/help.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/settings.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 static OUString
getInitials( const OUString
& rName
)
65 const sal_Unicode
* pStr
= rName
.getStr();
66 sal_Int32 nLength
= rName
.getLength();
71 while( nLength
&& (*pStr
<= ' ') )
79 sInitials
+= OUString( *pStr
);
83 // skip letters until whitespace
84 while( nLength
&& (*pStr
> ' ') )
93 class AnnotationDragMove
: public SdrDragMove
96 AnnotationDragMove(SdrDragView
& rNewView
, const rtl::Reference
<AnnotationTag
>& xTag
);
97 virtual bool BeginSdrDrag() SAL_OVERRIDE
;
98 virtual bool EndSdrDrag(bool bCopy
) SAL_OVERRIDE
;
99 virtual void MoveSdrDrag(const Point
& rNoSnapPnt
) SAL_OVERRIDE
;
100 virtual void CancelSdrDrag() SAL_OVERRIDE
;
103 rtl::Reference
<AnnotationTag
> mxTag
;
107 AnnotationDragMove::AnnotationDragMove(SdrDragView
& rNewView
, const rtl::Reference
<AnnotationTag
>& xTag
)
108 : SdrDragMove(rNewView
)
113 bool AnnotationDragMove::BeginSdrDrag()
115 DragStat().Ref1()=GetDragHdl()->GetPos();
116 DragStat().SetShown(!DragStat().IsShown());
118 maOrigin
= GetDragHdl()->GetPos();
119 DragStat().SetActionRect(Rectangle(maOrigin
,maOrigin
));
124 void AnnotationDragMove::MoveSdrDrag(const Point
& rNoSnapPnt
)
126 Point
aPnt(rNoSnapPnt
);
128 if (DragStat().CheckMinMoved(rNoSnapPnt
))
130 if (aPnt
!=DragStat().GetNow())
133 DragStat().NextMove(aPnt
);
134 GetDragHdl()->SetPos( maOrigin
+ Point( DragStat().GetDX(), DragStat().GetDY() ) );
136 DragStat().SetActionRect(Rectangle(aPnt
,aPnt
));
141 bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
145 mxTag
->Move( DragStat().GetDX(), DragStat().GetDY() );
149 void AnnotationDragMove::CancelSdrDrag()
154 class AnnotationHdl
: public SmartHdl
157 AnnotationHdl( const SmartTagReference
& xTag
, const Reference
< XAnnotation
>& xAnnotation
, const Point
& rPnt
);
158 virtual ~AnnotationHdl();
159 virtual void CreateB2dIAObject() SAL_OVERRIDE
;
160 virtual bool IsFocusHdl() const SAL_OVERRIDE
;
161 virtual bool isMarkable() const SAL_OVERRIDE
;
164 Reference
< XAnnotation
> mxAnnotation
;
165 rtl::Reference
< AnnotationTag
> mxTag
;
168 AnnotationHdl::AnnotationHdl( const SmartTagReference
& xTag
, const Reference
< XAnnotation
>& xAnnotation
, const Point
& rPnt
)
169 : SmartHdl( xTag
, rPnt
)
170 , mxAnnotation( xAnnotation
)
171 , mxTag( dynamic_cast< AnnotationTag
* >( xTag
.get() ) )
175 AnnotationHdl::~AnnotationHdl()
179 void AnnotationHdl::CreateB2dIAObject()
181 // first throw away old one
184 if( mxAnnotation
.is() )
186 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
188 const Point
aTagPos( GetPos() );
189 basegfx::B2DPoint
aPosition( aTagPos
.X(), aTagPos
.Y() );
191 const bool bFocused
= IsFocusHdl() && pHdlList
&& (pHdlList
->GetFocusHdl() == this);
193 BitmapEx
aBitmapEx( mxTag
->CreateAnnotationBitmap(mxTag
->isSelected()) );
196 aBitmapEx2
= mxTag
->CreateAnnotationBitmap(!mxTag
->isSelected() );
200 SdrMarkView
* pView
= pHdlList
->GetView();
202 if(pView
&& !pView
->areMarkHandlesHidden())
204 SdrPageView
* pPageView
= pView
->GetSdrPageView();
208 for(sal_uInt32 b
= 0; b
< pPageView
->PageWindowCount(); b
++)
210 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
211 const SdrPageWindow
& rPageWindow
= *pPageView
->GetPageWindow(b
);
213 SdrPaintWindow
& rPaintWindow
= rPageWindow
.GetPaintWindow();
214 rtl::Reference
< sdr::overlay::OverlayManager
> xManager
= rPageWindow
.GetOverlayManager();
215 if(rPaintWindow
.OutputToWindow() && xManager
.is() )
217 sdr::overlay::OverlayObject
* pOverlayObject
= 0;
219 // animate focused handles
222 const sal_uInt64 nBlinkTime
= rStyleSettings
.GetCursorBlinkTime();
224 pOverlayObject
= new sdr::overlay::OverlayAnimatedBitmapEx(aPosition
, aBitmapEx
, aBitmapEx2
, nBlinkTime
, 0, 0, 0, 0 );
228 pOverlayObject
= new sdr::overlay::OverlayBitmapEx( aPosition
, aBitmapEx
, 0, 0 );
231 xManager
->add(*pOverlayObject
);
232 maOverlayGroup
.append(*pOverlayObject
);
241 bool AnnotationHdl::IsFocusHdl() const
246 bool AnnotationHdl::isMarkable() const
251 AnnotationTag::AnnotationTag( AnnotationManagerImpl
& rManager
, ::sd::View
& rView
, const Reference
< XAnnotation
>& xAnnotation
, Color
& rColor
, int nIndex
, const vcl::Font
& rFont
)
253 , mrManager( rManager
)
254 , mxAnnotation( xAnnotation
)
258 , mnClosePopupEvent( 0 )
259 , mpListenWindow( 0 )
263 AnnotationTag::~AnnotationTag()
265 DBG_ASSERT( !mxAnnotation
.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
269 /** returns true if the AnnotationTag handled the event. */
270 bool AnnotationTag::MouseButtonDown( const MouseEvent
& rMEvt
, SmartHdl
& /*rHdl*/ )
272 if( !mxAnnotation
.is() )
278 SmartTagReference
xTag( this );
279 mrView
.getSmartTags().select( xTag
);
283 if( rMEvt
.IsLeft() && !rMEvt
.IsRight() )
285 vcl::Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
288 maMouseDownPos
= pWindow
->PixelToLogic( rMEvt
.GetPosPixel() );
291 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
293 mpListenWindow
= pWindow
;
294 mpListenWindow
->AddEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
303 /** returns true if the SmartTag consumes this event. */
304 bool AnnotationTag::KeyInput( const KeyEvent
& rKEvt
)
306 if( !mxAnnotation
.is() )
309 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
313 mrManager
.DeleteAnnotation( mxAnnotation
);
320 return OnMove( rKEvt
);
324 SmartTagReference
xThis( this );
325 mrView
.getSmartTags().deselect();
330 mrManager
.SelectNextAnnotation(!rKEvt
.GetKeyCode().IsShift());
343 /** returns true if the SmartTag consumes this event. */
344 bool AnnotationTag::RequestHelp( const HelpEvent
& /*rHEvt*/ )
350 /** returns true if the SmartTag consumes this event. */
351 bool AnnotationTag::Command( const CommandEvent
& rCEvt
)
353 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
355 vcl::Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
358 Rectangle
aContextRect(rCEvt
.GetMousePosPixel(),Size(1,1));
359 mrManager
.ExecuteAnnotationContextMenu( mxAnnotation
, pWindow
, aContextRect
);
367 void AnnotationTag::Move( int nDX
, int nDY
)
369 if( mxAnnotation
.is() )
371 if( mrManager
.GetDoc()->IsUndoEnabled() )
372 mrManager
.GetDoc()->BegUndo( SD_RESSTR( STR_ANNOTATION_UNDO_MOVE
) );
374 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
375 aPosition
.X
+= (double)nDX
/ 100.0;
376 aPosition
.Y
+= (double)nDY
/ 100.0;
377 mxAnnotation
->setPosition( aPosition
);
379 if( mrManager
.GetDoc()->IsUndoEnabled() )
380 mrManager
.GetDoc()->EndUndo();
382 mrView
.updateHandles();
386 bool AnnotationTag::OnMove( const KeyEvent
& rKEvt
)
391 switch( rKEvt
.GetKeyCode().GetCode() )
393 case KEY_UP
: nY
= -1; break;
394 case KEY_DOWN
: nY
= 1; break;
395 case KEY_LEFT
: nX
= -1; break;
396 case KEY_RIGHT
: nX
= 1; break;
400 if(rKEvt
.GetKeyCode().IsMod2())
402 OutputDevice
* pOut
= mrView
.GetViewShell()->GetActiveWindow();
403 Size aLogicSizeOnePixel
= (pOut
) ? pOut
->PixelToLogic(Size(1,1)) : Size(100, 100);
404 nX
*= aLogicSizeOnePixel
.Width();
405 nY
*= aLogicSizeOnePixel
.Height();
409 // old, fixed move distance
416 // move the annotation
423 void AnnotationTag::CheckPossibilities()
427 sal_uLong
AnnotationTag::GetMarkablePointCount() const
432 sal_uLong
AnnotationTag::GetMarkedPointCount() const
437 bool AnnotationTag::MarkPoint(SdrHdl
& /*rHdl*/, bool /*bUnmark*/ )
443 bool AnnotationTag::MarkPoints(const Rectangle
* /*pRect*/, bool /*bUnmark*/ )
449 bool AnnotationTag::getContext( SdrViewContext
& /*rContext*/ )
454 void AnnotationTag::addCustomHandles( SdrHdlList
& rHandlerList
)
456 if( mxAnnotation
.is() )
458 SmartTagReference
xThis( this );
460 AnnotationHdl
* pHdl
= new AnnotationHdl( xThis
, mxAnnotation
, aPoint
);
461 pHdl
->SetObjHdlNum( SMART_TAG_HDL_NUM
);
462 pHdl
->SetPageView( mrView
.GetSdrPageView() );
464 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
465 Point
aBasePos( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) );
466 pHdl
->SetPos( aBasePos
);
468 rHandlerList
.AddHdl( pHdl
);
472 void AnnotationTag::disposing()
476 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
479 if( mnClosePopupEvent
)
481 Application::RemoveUserEvent( mnClosePopupEvent
);
482 mnClosePopupEvent
= 0;
485 mxAnnotation
.clear();
487 SmartTag::disposing();
490 void AnnotationTag::select()
494 mrManager
.onTagSelected( *this );
496 vcl::Window
* pWindow
= mrView
.GetViewShell()->GetActiveWindow();
499 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
500 Point
aPos( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) );
502 Rectangle
aVisRect( aPos
, pWindow
->PixelToLogic(maSize
) );
503 mrView
.MakeVisible(aVisRect
, *pWindow
);
507 void AnnotationTag::deselect()
509 SmartTag::deselect();
513 mrManager
.onTagDeselected( *this );
516 BitmapEx
AnnotationTag::CreateAnnotationBitmap( bool bSelected
)
518 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
520 OUString
sAuthor( getInitials( mxAnnotation
->getAuthor() ) );
521 sAuthor
+= OUString( ' ' );
522 sAuthor
+= OUString::number( mnIndex
);
524 pVDev
->SetFont( mrFont
);
526 const int BORDER_X
= 4; // pixels
527 const int BORDER_Y
= 4; // pixels
529 maSize
= Size( pVDev
->GetTextWidth( sAuthor
) + 2*BORDER_X
, pVDev
->GetTextHeight() + 2*BORDER_Y
);
530 pVDev
->SetOutputSizePixel( maSize
, false );
532 Color
aBorderColor( maColor
);
536 aBorderColor
.Invert();
540 if( maColor
.IsDark() )
542 aBorderColor
.IncreaseLuminance( 32 );
546 aBorderColor
.DecreaseLuminance( 32 );
551 Rectangle
aBorderRect( aPos
, maSize
);
552 pVDev
->SetLineColor(aBorderColor
);
553 pVDev
->SetFillColor(maColor
);
554 pVDev
->DrawRect( aBorderRect
);
556 pVDev
->SetTextColor( maColor
.IsDark() ? COL_WHITE
: COL_BLACK
);
557 pVDev
->DrawText( Point( BORDER_X
, BORDER_Y
), sAuthor
);
559 return pVDev
->GetBitmapEx( aPos
, maSize
);
562 void AnnotationTag::OpenPopup( bool bEdit
)
564 if( !mxAnnotation
.is() )
567 if( !mpAnnotationWindow
.get() )
569 vcl::Window
* pWindow
= dynamic_cast< vcl::Window
* >( getView().GetFirstOutputDevice() );
572 RealPoint2D
aPosition( mxAnnotation
->getPosition() );
573 Point
aPos( pWindow
->OutputToScreenPixel( pWindow
->LogicToPixel( Point( static_cast<long>(aPosition
.X
* 100.0), static_cast<long>(aPosition
.Y
* 100.0) ) ) ) );
575 aPos
.X() += 4; // magic!
578 Rectangle
aRect( aPos
, maSize
);
580 mpAnnotationWindow
.reset( VclPtr
<AnnotationWindow
>::Create( mrManager
, mrView
.GetDocSh(), pWindow
->GetWindow(GetWindowType::Frame
) ) );
581 mpAnnotationWindow
->InitControls();
582 mpAnnotationWindow
->setAnnotation(mxAnnotation
);
584 sal_uInt16 nArrangeIndex
= 0;
585 Point
aPopupPos( FloatingWindow::CalcFloatingPosition( mpAnnotationWindow
.get(), aRect
, FloatWinPopupFlags::Right
, nArrangeIndex
) );
586 Size
aPopupSize( 320, 240 );
588 mpAnnotationWindow
->SetPosSizePixel( aPopupPos
, aPopupSize
);
589 mpAnnotationWindow
->DoResize();
591 mpAnnotationWindow
->Show();
592 mpAnnotationWindow
->GrabFocus();
593 mpAnnotationWindow
->AddEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
597 if( bEdit
&& mpAnnotationWindow
.get() )
598 mpAnnotationWindow
->StartEdit();
601 void AnnotationTag::ClosePopup()
603 if( mpAnnotationWindow
.get() )
605 mpAnnotationWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
606 mpAnnotationWindow
->Deactivate();
607 mpAnnotationWindow
.disposeAndClear();
611 IMPL_LINK(AnnotationTag
, WindowEventHandler
, VclWindowEvent
*, pEvent
)
615 vcl::Window
* pWindow
= pEvent
->GetWindow();
619 if( pWindow
== mpAnnotationWindow
.get() )
621 if( pEvent
->GetId() == VCLEVENT_WINDOW_DEACTIVATE
)
623 if( mnClosePopupEvent
)
624 Application::RemoveUserEvent( mnClosePopupEvent
);
626 mnClosePopupEvent
= Application::PostUserEvent( LINK( this, AnnotationTag
, ClosePopupHdl
) );
629 else if( pWindow
== mpListenWindow
)
631 switch( pEvent
->GetId() )
633 case VCLEVENT_WINDOW_MOUSEBUTTONUP
:
635 // if we stop pressing the button without a mouse move we open the popup
636 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
638 if( mpAnnotationWindow
.get() == 0 )
642 case VCLEVENT_WINDOW_MOUSEMOVE
:
644 // if we move the mouse after a button down we wan't to start draging
645 mpListenWindow
->RemoveEventListener( LINK(this, AnnotationTag
, WindowEventHandler
));
648 SdrHdl
* pHdl
= mrView
.PickHandle(maMouseDownPos
);
652 const sal_uInt16 nDrgLog
= (sal_uInt16
)pWindow
->PixelToLogic(Size(DRGPIX
,0)).Width();
654 rtl::Reference
< AnnotationTag
> xTag( this );
656 SdrDragMethod
* pDragMethod
= new AnnotationDragMove( mrView
, xTag
);
657 mrView
.BegDragObj(maMouseDownPos
, NULL
, pHdl
, nDrgLog
, pDragMethod
);
661 case VCLEVENT_OBJECT_DYING
:
668 return sal_IntPtr(true);
671 IMPL_LINK_NOARG(AnnotationTag
, ClosePopupHdl
)
673 mnClosePopupEvent
= 0;
678 } // end of namespace sd
680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */