bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / annotations / annotationtag.cxx
blob4faec9617f24ac9f175d31fce42927ddcdf9536d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
37 #include "View.hxx"
38 #include "sdresid.hxx"
39 #include "annotations.hrc"
40 #include "annotationmanagerimpl.hxx"
41 #include "annotationwindow.hxx"
42 #include "annotationtag.hxx"
43 #include "sdpage.hxx"
44 #include "ViewShell.hxx"
45 #include "app.hrc"
46 #include "Window.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;
55 namespace sd
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 )
63 OUString sInitials;
65 const sal_Unicode * pStr = rName.getStr();
66 sal_Int32 nLength = rName.getLength();
68 while( nLength )
70 // skip whitespace
71 while( nLength && (*pStr <= ' ') )
73 nLength--; pStr++;
76 // take letter
77 if( nLength )
79 sInitials += OUString( *pStr );
80 nLength--; pStr++;
83 // skip letters until whitespace
84 while( nLength && (*pStr > ' ') )
86 nLength--; pStr++;
90 return sInitials;
93 class AnnotationDragMove : public SdrDragMove
95 public:
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;
102 private:
103 rtl::Reference <AnnotationTag > mxTag;
104 Point maOrigin;
107 AnnotationDragMove::AnnotationDragMove(SdrDragView& rNewView, const rtl::Reference <AnnotationTag >& xTag)
108 : SdrDragMove(rNewView)
109 , mxTag( xTag )
113 bool AnnotationDragMove::BeginSdrDrag()
115 DragStat().Ref1()=GetDragHdl()->GetPos();
116 DragStat().SetShown(!DragStat().IsShown());
118 maOrigin = GetDragHdl()->GetPos();
119 DragStat().SetActionRect(Rectangle(maOrigin,maOrigin));
121 return true;
124 void AnnotationDragMove::MoveSdrDrag(const Point& rNoSnapPnt)
126 Point aPnt(rNoSnapPnt);
128 if (DragStat().CheckMinMoved(rNoSnapPnt))
130 if (aPnt!=DragStat().GetNow())
132 Hide();
133 DragStat().NextMove(aPnt);
134 GetDragHdl()->SetPos( maOrigin + Point( DragStat().GetDX(), DragStat().GetDY() ) );
135 Show();
136 DragStat().SetActionRect(Rectangle(aPnt,aPnt));
141 bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
143 Hide();
144 if( mxTag.is() )
145 mxTag->Move( DragStat().GetDX(), DragStat().GetDY() );
146 return true;
149 void AnnotationDragMove::CancelSdrDrag()
151 Hide();
154 class AnnotationHdl : public SmartHdl
156 public:
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;
163 private:
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
182 GetRidOfIAObject();
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()) );
194 BitmapEx aBitmapEx2;
195 if( bFocused )
196 aBitmapEx2 = mxTag->CreateAnnotationBitmap(!mxTag->isSelected() );
198 if(pHdlList)
200 SdrMarkView* pView = pHdlList->GetView();
202 if(pView && !pView->areMarkHandlesHidden())
204 SdrPageView* pPageView = pView->GetSdrPageView();
206 if(pPageView)
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
220 if(bFocused)
222 const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
224 pOverlayObject = new sdr::overlay::OverlayAnimatedBitmapEx(aPosition, aBitmapEx, aBitmapEx2, nBlinkTime, 0, 0, 0, 0 );
226 else
228 pOverlayObject = new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 );
231 xManager->add(*pOverlayObject);
232 maOverlayGroup.append(*pOverlayObject);
241 bool AnnotationHdl::IsFocusHdl() const
243 return true;
246 bool AnnotationHdl::isMarkable() const
248 return false;
251 AnnotationTag::AnnotationTag( AnnotationManagerImpl& rManager, ::sd::View& rView, const Reference< XAnnotation >& xAnnotation, Color& rColor, int nIndex, const vcl::Font& rFont )
252 : SmartTag( rView )
253 , mrManager( rManager )
254 , mxAnnotation( xAnnotation )
255 , maColor( rColor )
256 , mnIndex( nIndex )
257 , mrFont( rFont )
258 , mnClosePopupEvent( 0 )
259 , mpListenWindow( 0 )
263 AnnotationTag::~AnnotationTag()
265 DBG_ASSERT( !mxAnnotation.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
266 Dispose();
269 /** returns true if the AnnotationTag handled the event. */
270 bool AnnotationTag::MouseButtonDown( const MouseEvent& rMEvt, SmartHdl& /*rHdl*/ )
272 if( !mxAnnotation.is() )
273 return false;
275 bool bRet = false;
276 if( !isSelected() )
278 SmartTagReference xTag( this );
279 mrView.getSmartTags().select( xTag );
280 bRet = true;
283 if( rMEvt.IsLeft() && !rMEvt.IsRight() )
285 vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
286 if( pWindow )
288 maMouseDownPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
290 if( mpListenWindow )
291 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
293 mpListenWindow = pWindow;
294 mpListenWindow->AddEventListener( LINK(this, AnnotationTag, WindowEventHandler));
297 bRet = true;
300 return bRet;
303 /** returns true if the SmartTag consumes this event. */
304 bool AnnotationTag::KeyInput( const KeyEvent& rKEvt )
306 if( !mxAnnotation.is() )
307 return false;
309 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
310 switch( nCode )
312 case KEY_DELETE:
313 mrManager.DeleteAnnotation( mxAnnotation );
314 return true;
316 case KEY_DOWN:
317 case KEY_UP:
318 case KEY_LEFT:
319 case KEY_RIGHT:
320 return OnMove( rKEvt );
322 case KEY_ESCAPE:
324 SmartTagReference xThis( this );
325 mrView.getSmartTags().deselect();
326 return true;
329 case KEY_TAB:
330 mrManager.SelectNextAnnotation(!rKEvt.GetKeyCode().IsShift());
331 return true;
333 case KEY_RETURN:
334 case KEY_SPACE:
335 OpenPopup( true );
336 return true;
338 default:
339 return false;
343 /** returns true if the SmartTag consumes this event. */
344 bool AnnotationTag::RequestHelp( const HelpEvent& /*rHEvt*/ )
347 return false;
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();
356 if( pWindow )
358 Rectangle aContextRect(rCEvt.GetMousePosPixel(),Size(1,1));
359 mrManager.ExecuteAnnotationContextMenu( mxAnnotation, pWindow, aContextRect );
360 return true;
364 return false;
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 )
388 long nX = 0;
389 long nY = 0;
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;
397 default: 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();
407 else
409 // old, fixed move distance
410 nX *= 100;
411 nY *= 100;
414 if( nX || nY )
416 // move the annotation
417 Move( nX, nY );
420 return true;
423 void AnnotationTag::CheckPossibilities()
427 sal_uLong AnnotationTag::GetMarkablePointCount() const
429 return 0;
432 sal_uLong AnnotationTag::GetMarkedPointCount() const
434 return 0;
437 bool AnnotationTag::MarkPoint(SdrHdl& /*rHdl*/, bool /*bUnmark*/ )
439 bool bRet=false;
440 return bRet;
443 bool AnnotationTag::MarkPoints(const Rectangle* /*pRect*/, bool /*bUnmark*/ )
445 bool bChgd=false;
446 return bChgd;
449 bool AnnotationTag::getContext( SdrViewContext& /*rContext*/ )
451 return false;
454 void AnnotationTag::addCustomHandles( SdrHdlList& rHandlerList )
456 if( mxAnnotation.is() )
458 SmartTagReference xThis( this );
459 Point aPoint;
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()
474 if( mpListenWindow )
476 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
479 if( mnClosePopupEvent )
481 Application::RemoveUserEvent( mnClosePopupEvent );
482 mnClosePopupEvent = 0;
485 mxAnnotation.clear();
486 ClosePopup();
487 SmartTag::disposing();
490 void AnnotationTag::select()
492 SmartTag::select();
494 mrManager.onTagSelected( *this );
496 vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
497 if( pWindow )
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();
511 ClosePopup();
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 );
534 if( bSelected )
536 aBorderColor.Invert();
538 else
540 if( maColor.IsDark() )
542 aBorderColor.IncreaseLuminance( 32 );
544 else
546 aBorderColor.DecreaseLuminance( 32 );
550 Point aPos;
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() )
565 return;
567 if( !mpAnnotationWindow.get() )
569 vcl::Window* pWindow = dynamic_cast< vcl::Window* >( getView().GetFirstOutputDevice() );
570 if( pWindow )
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!
576 aPos.Y() += 1;
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)
613 if( pEvent != NULL )
615 vcl::Window* pWindow = pEvent->GetWindow();
617 if( pWindow )
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));
637 mpListenWindow = 0;
638 if( mpAnnotationWindow.get() == 0 )
639 OpenPopup(false);
641 break;
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));
646 mpListenWindow = 0;
648 SdrHdl* pHdl = mrView.PickHandle(maMouseDownPos);
649 if( pHdl )
651 mrView.BrkAction();
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 );
660 break;
661 case VCLEVENT_OBJECT_DYING:
662 mpListenWindow = 0;
663 break;
668 return sal_IntPtr(true);
671 IMPL_LINK_NOARG(AnnotationTag, ClosePopupHdl)
673 mnClosePopupEvent = 0;
674 ClosePopup();
675 return 0;
678 } // end of namespace sd
680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */