bump product version to 4.1.6.2
[LibreOffice.git] / sd / source / ui / annotations / annotationtag.cxx
blob53b6f7de2d53d664fb6dc8c4e07c203c769a9381
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 .
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>
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 // --------------------------------------------------------------------
63 static OUString getInitials( const OUString& rName )
65 OUString sInitials;
67 const sal_Unicode * pStr = rName.getStr();
68 sal_Int32 nLength = rName.getLength();
70 while( nLength )
72 // skip whitespace
73 while( nLength && (*pStr <= ' ') )
75 nLength--; pStr++;
78 // take letter
79 if( nLength )
81 sInitials += OUString( *pStr );
82 nLength--; pStr++;
85 // skip letters until whitespace
86 while( nLength && (*pStr > ' ') )
88 nLength--; pStr++;
92 return sInitials;
95 // --------------------------------------------------------------------
97 // --------------------------------------------------------------------
99 class AnnotationDragMove : public SdrDragMove
101 public:
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();
108 private:
109 rtl::Reference <AnnotationTag > mxTag;
110 Point maOrigin;
113 AnnotationDragMove::AnnotationDragMove(SdrDragView& rNewView, const rtl::Reference <AnnotationTag >& xTag)
114 : SdrDragMove(rNewView)
115 , mxTag( xTag )
119 bool AnnotationDragMove::BeginSdrDrag()
121 DragStat().Ref1()=GetDragHdl()->GetPos();
122 DragStat().SetShown(!DragStat().IsShown());
124 maOrigin = GetDragHdl()->GetPos();
125 DragStat().SetActionRect(Rectangle(maOrigin,maOrigin));
127 return true;
130 void AnnotationDragMove::MoveSdrDrag(const Point& rNoSnapPnt)
132 Point aPnt(rNoSnapPnt);
134 if (DragStat().CheckMinMoved(rNoSnapPnt))
136 if (aPnt!=DragStat().GetNow())
138 Hide();
139 DragStat().NextMove(aPnt);
140 GetDragHdl()->SetPos( maOrigin + Point( DragStat().GetDX(), DragStat().GetDY() ) );
141 Show();
142 DragStat().SetActionRect(Rectangle(aPnt,aPnt));
147 bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
149 Hide();
150 if( mxTag.is() )
151 mxTag->Move( DragStat().GetDX(), DragStat().GetDY() );
152 return sal_True;
155 void AnnotationDragMove::CancelSdrDrag()
157 Hide();
160 // --------------------------------------------------------------------
162 class AnnotationHdl : public SmartHdl
164 public:
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;
173 private:
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
198 GetRidOfIAObject();
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()) );
210 BitmapEx aBitmapEx2;
211 if( bFocused )
212 aBitmapEx2 = mxTag->CreateAnnotationBitmap(!mxTag->isSelected() );
214 if(pHdlList)
216 SdrMarkView* pView = pHdlList->GetView();
218 if(pView && !pView->areMarkHandlesHidden())
220 SdrPageView* pPageView = pView->GetSdrPageView();
222 if(pPageView)
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
236 if(bFocused)
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 );
242 else
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
261 return sal_True;
264 // --------------------------------------------------------------------
266 bool AnnotationHdl::isMarkable() const
268 return false;
271 // --------------------------------------------------------------------
273 Pointer AnnotationHdl::GetSdrDragPointer() const
275 PointerStyle eStyle = POINTER_NOTALLOWED;
276 if( mxTag.is() )
278 if( mxTag->isSelected() )
280 eStyle = POINTER_MOVE;
282 else
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 )
294 : SmartTag( rView )
295 , mrManager( rManager )
296 , mxAnnotation( xAnnotation )
297 , maColor( rColor )
298 , mnIndex( nIndex )
299 , mrFont( rFont )
300 , mnClosePopupEvent( 0 )
301 , mpListenWindow( 0 )
305 // --------------------------------------------------------------------
307 AnnotationTag::~AnnotationTag()
309 DBG_ASSERT( !mxAnnotation.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
310 Dispose();
313 // --------------------------------------------------------------------
315 /** returns true if the AnnotationTag handled the event. */
316 bool AnnotationTag::MouseButtonDown( const MouseEvent& rMEvt, SmartHdl& /*rHdl*/ )
318 if( !mxAnnotation.is() )
319 return false;
321 bool bRet = false;
322 if( !isSelected() )
324 SmartTagReference xTag( this );
325 mrView.getSmartTags().select( xTag );
326 bRet = true;
329 if( rMEvt.IsLeft() && !rMEvt.IsRight() )
331 Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
332 if( pWindow )
334 maMouseDownPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
336 if( mpListenWindow )
337 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
339 mpListenWindow = pWindow;
340 mpListenWindow->AddEventListener( LINK(this, AnnotationTag, WindowEventHandler));
343 bRet = true;
346 return bRet;
349 // --------------------------------------------------------------------
351 /** returns true if the SmartTag consumes this event. */
352 bool AnnotationTag::KeyInput( const KeyEvent& rKEvt )
354 if( !mxAnnotation.is() )
355 return false;
357 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
358 switch( nCode )
360 case KEY_DELETE:
361 mrManager.DeleteAnnotation( mxAnnotation );
362 return true;
364 case KEY_DOWN:
365 case KEY_UP:
366 case KEY_LEFT:
367 case KEY_RIGHT:
368 return OnMove( rKEvt );
370 case KEY_ESCAPE:
372 SmartTagReference xThis( this );
373 mrView.getSmartTags().deselect();
374 return true;
377 case KEY_TAB:
378 mrManager.SelectNextAnnotation(!rKEvt.GetKeyCode().IsShift());
379 return true;
381 case KEY_RETURN:
382 case KEY_SPACE:
383 OpenPopup( true );
384 return true;
386 default:
387 return false;
391 /** returns true if the SmartTag consumes this event. */
392 bool AnnotationTag::RequestHelp( const HelpEvent& /*rHEvt*/ )
395 return false;
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();
404 if( pWindow )
406 Rectangle aContextRect(rCEvt.GetMousePosPixel(),Size(1,1));
407 mrManager.ExecuteAnnotationContextMenu( mxAnnotation, pWindow, aContextRect );
408 return true;
412 return false;
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 )
436 long nX = 0;
437 long nY = 0;
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;
445 default: 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();
455 else
457 // old, fixed move distance
458 nX *= 100;
459 nY *= 100;
462 if( nX || nY )
464 // move the annotation
465 Move( nX, nY );
468 return true;
471 // --------------------------------------------------------------------
473 void AnnotationTag::CheckPossibilities()
477 // --------------------------------------------------------------------
479 sal_uLong AnnotationTag::GetMarkablePointCount() const
481 return 0;
484 // --------------------------------------------------------------------
486 sal_uLong AnnotationTag::GetMarkedPointCount() const
488 return 0;
491 // --------------------------------------------------------------------
493 sal_Bool AnnotationTag::MarkPoint(SdrHdl& /*rHdl*/, sal_Bool /*bUnmark*/ )
495 sal_Bool bRet=sal_False;
496 return bRet;
499 // --------------------------------------------------------------------
501 sal_Bool AnnotationTag::MarkPoints(const Rectangle* /*pRect*/, sal_Bool /*bUnmark*/ )
503 sal_Bool bChgd=sal_False;
504 return bChgd;
507 // --------------------------------------------------------------------
509 bool AnnotationTag::getContext( SdrViewContext& /*rContext*/ )
511 return false;
514 // --------------------------------------------------------------------
516 void AnnotationTag::addCustomHandles( SdrHdlList& rHandlerList )
518 if( mxAnnotation.is() )
520 SmartTagReference xThis( this );
521 Point aPoint;
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()
538 if( mpListenWindow )
540 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
543 if( mnClosePopupEvent )
545 Application::RemoveUserEvent( mnClosePopupEvent );
546 mnClosePopupEvent = 0;
549 mxAnnotation.clear();
550 ClosePopup();
551 SmartTag::disposing();
554 // --------------------------------------------------------------------
556 void AnnotationTag::select()
558 SmartTag::select();
560 mrManager.onTagSelected( *this );
562 Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
563 if( pWindow )
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();
579 ClosePopup();
581 mrManager.onTagDeselected( *this );
584 // --------------------------------------------------------------------
586 BitmapEx AnnotationTag::CreateAnnotationBitmap( bool bSelected )
588 VirtualDevice aVDev;
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 );
604 if( bSelected )
606 aBorderColor.Invert();
608 else
610 if( maColor.IsDark() )
612 aBorderColor.IncreaseLuminance( 32 );
614 else
616 aBorderColor.DecreaseLuminance( 32 );
620 Point aPos;
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() )
635 return;
637 if( !mpAnnotationWindow.get() )
639 ::Window* pWindow = dynamic_cast< ::Window* >( getView().GetFirstOutputDevice() );
640 if( pWindow )
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!
646 aPos.Y() += 1;
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)
683 if( pEvent != NULL )
685 ::Window* pWindow = pEvent->GetWindow();
687 if( pWindow )
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));
707 mpListenWindow = 0;
708 if( mpAnnotationWindow.get() == 0 )
709 OpenPopup(false);
711 break;
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));
716 mpListenWindow = 0;
718 SdrHdl* pHdl = mrView.PickHandle(maMouseDownPos);
719 if( pHdl )
721 mrView.BrkAction();
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 );
730 break;
731 case VCLEVENT_OBJECT_DYING:
732 mpListenWindow = 0;
733 break;
738 return sal_True;
741 IMPL_LINK_NOARG(AnnotationTag, ClosePopupHdl)
743 mnClosePopupEvent = 0;
744 ClosePopup();
745 return 0;
748 } // end of namespace sd
750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */