android: Update app-specific/MIME type icons
[LibreOffice.git] / sd / source / ui / annotations / annotationtag.cxx
blobdbadf4cb6fe1ad24f0a37e2f36a2cab50d8db87f
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/geometry/RealPoint2D.hpp>
21 #include <com/sun/star/office/XAnnotation.hpp>
23 #include <rtl/ustrbuf.hxx>
25 #include <utility>
26 #include <vcl/commandevent.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/weldutils.hxx>
31 #include <svx/sdr/overlay/overlayanimatedbitmapex.hxx>
32 #include <svx/sdr/overlay/overlaybitmapex.hxx>
33 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
34 #include <svx/svdpagv.hxx>
35 #include <svx/sdrpagewindow.hxx>
36 #include <svx/sdrpaintwindow.hxx>
37 #include <svx/svddrgmt.hxx>
38 #include <tools/debug.hxx>
40 #include <View.hxx>
41 #include <sdresid.hxx>
42 #include <strings.hrc>
43 #include "annotationmanagerimpl.hxx"
44 #include "annotationwindow.hxx"
45 #include "annotationtag.hxx"
46 #include <Annotation.hxx>
47 #include <ViewShell.hxx>
48 #include <Window.hxx>
49 #include <drawdoc.hxx>
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::lang;
53 using namespace ::com::sun::star::drawing;
54 using namespace ::com::sun::star::office;
55 using namespace ::com::sun::star::geometry;
57 namespace sd
60 const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32;
61 const int DRGPIX = 2; // Drag MinMove in Pixel
63 static OUString getInitials( const OUString& rName )
65 OUStringBuffer 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.append(*pStr);
82 nLength--; pStr++;
85 // skip letters until whitespace
86 while( nLength && (*pStr > ' ') )
88 nLength--; pStr++;
92 return sInitials.makeStringAndClear();
95 namespace {
97 class AnnotationDragMove : public SdrDragMove
99 public:
100 AnnotationDragMove(SdrDragView& rNewView, rtl::Reference <AnnotationTag > xTag);
101 virtual bool BeginSdrDrag() override;
102 virtual bool EndSdrDrag(bool bCopy) override;
103 virtual void MoveSdrDrag(const Point& rNoSnapPnt) override;
104 virtual void CancelSdrDrag() override;
106 private:
107 rtl::Reference <AnnotationTag > mxTag;
108 Point maOrigin;
113 AnnotationDragMove::AnnotationDragMove(SdrDragView& rNewView, rtl::Reference <AnnotationTag > xTag)
114 : SdrDragMove(rNewView)
115 , mxTag(std::move( xTag ))
119 bool AnnotationDragMove::BeginSdrDrag()
121 DragStat().SetRef1(GetDragHdl()->GetPos());
122 DragStat().SetShown(!DragStat().IsShown());
124 maOrigin = GetDragHdl()->GetPos();
125 DragStat().SetActionRect(::tools::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(::tools::Rectangle(aPnt,aPnt));
147 bool AnnotationDragMove::EndSdrDrag(bool /*bCopy*/)
149 Hide();
150 if( mxTag.is() )
151 mxTag->Move( DragStat().GetDX(), DragStat().GetDY() );
152 return true;
155 void AnnotationDragMove::CancelSdrDrag()
157 Hide();
160 namespace {
162 class AnnotationHdl : public SmartHdl
164 public:
165 AnnotationHdl( const SmartTagReference& xTag, const Reference< XAnnotation >& xAnnotation, const Point& rPnt );
167 virtual void CreateB2dIAObject() override;
168 virtual bool IsFocusHdl() const override;
170 private:
171 Reference< XAnnotation > mxAnnotation;
172 rtl::Reference< AnnotationTag > mxTag;
177 AnnotationHdl::AnnotationHdl( const SmartTagReference& xTag, const Reference< XAnnotation >& xAnnotation, const Point& rPnt )
178 : SmartHdl( xTag, rPnt, SdrHdlKind::SmartTag )
179 , mxAnnotation( xAnnotation )
180 , mxTag( dynamic_cast< AnnotationTag* >( xTag.get() ) )
184 void AnnotationHdl::CreateB2dIAObject()
186 // first throw away old one
187 GetRidOfIAObject();
189 if (!mxAnnotation.is())
190 return;
192 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
194 const Point aTagPos( GetPos() );
195 basegfx::B2DPoint aPosition( aTagPos.X(), aTagPos.Y() );
197 const bool bFocused = IsFocusHdl() && pHdlList && (pHdlList->GetFocusHdl() == this);
199 BitmapEx aBitmapEx( mxTag->CreateAnnotationBitmap(mxTag->isSelected()) );
200 BitmapEx aBitmapEx2;
201 if( bFocused )
202 aBitmapEx2 = mxTag->CreateAnnotationBitmap(!mxTag->isSelected() );
204 if(!pHdlList)
205 return;
207 SdrMarkView* pView = pHdlList->GetView();
209 if(!pView || pView->areMarkHandlesHidden())
210 return;
212 SdrPageView* pPageView = pView->GetSdrPageView();
214 if(!pPageView)
215 return;
217 for(sal_uInt32 b = 0; b < pPageView->PageWindowCount(); b++)
219 // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b];
220 const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b);
222 SdrPaintWindow& rPaintWindow = rPageWindow.GetPaintWindow();
223 const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager();
224 if(rPaintWindow.OutputToWindow() && xManager.is() )
226 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject;
228 auto* pAnnotation = dynamic_cast<sd::Annotation*>(mxAnnotation.get());
230 if (pAnnotation && pAnnotation->hasCustomAnnotationMarker())
232 CustomAnnotationMarker& rCustomAnnotationMarker = pAnnotation->getCustomAnnotationMarker();
234 auto& rPolygons = rCustomAnnotationMarker.maPolygons;
235 if (!rPolygons.empty())
237 basegfx::B2DPolyPolygon aPolyPolygon;
238 for (auto const & rPolygon : rPolygons)
239 aPolyPolygon.append(rPolygon);
241 pOverlayObject.reset(new sdr::overlay::OverlayPolyPolygon(
242 std::move(aPolyPolygon),
243 rCustomAnnotationMarker.maLineColor,
244 rCustomAnnotationMarker.mnLineWidth,
245 rCustomAnnotationMarker.maFillColor));
248 else
250 // animate focused handles
251 if(bFocused)
253 const sal_uInt64 nBlinkTime = rStyleSettings.GetCursorBlinkTime();
255 pOverlayObject.reset(new sdr::overlay::OverlayAnimatedBitmapEx(aPosition, aBitmapEx, aBitmapEx2, nBlinkTime, 0, 0, 0, 0 ));
257 else
259 pOverlayObject.reset(new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 ));
263 // OVERLAYMANAGER
264 insertNewlyCreatedOverlayObjectForSdrHdl(
265 std::move(pOverlayObject),
266 rPageWindow.GetObjectContact(),
267 *xManager);
272 bool AnnotationHdl::IsFocusHdl() const
274 return true;
277 AnnotationTag::AnnotationTag( AnnotationManagerImpl& rManager, ::sd::View& rView, const Reference< XAnnotation >& xAnnotation, Color const & rColor, int nIndex, const vcl::Font& rFont )
278 : SmartTag( rView )
279 , mrManager( rManager )
280 , mxAnnotation( xAnnotation )
281 , maColor( rColor )
282 , mnIndex( nIndex )
283 , mrFont( rFont )
284 , mpListenWindow( nullptr )
288 AnnotationTag::~AnnotationTag()
290 DBG_ASSERT( !mxAnnotation.is(), "sd::AnnotationTag::~AnnotationTag(), dispose me first!" );
291 Dispose();
294 /** returns true if the AnnotationTag handled the event. */
295 bool AnnotationTag::MouseButtonDown( const MouseEvent& rMEvt, SmartHdl& /*rHdl*/ )
297 if( !mxAnnotation.is() )
298 return false;
300 bool bRet = false;
301 if( !isSelected() )
303 SmartTagReference xTag( this );
304 mrView.getSmartTags().select( xTag );
305 bRet = true;
308 if( rMEvt.IsLeft() && !rMEvt.IsRight() )
310 vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
311 if( pWindow )
313 maMouseDownPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
315 if( mpListenWindow )
316 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
318 mpListenWindow = pWindow;
319 mpListenWindow->AddEventListener( LINK(this, AnnotationTag, WindowEventHandler));
322 bRet = true;
325 return bRet;
328 /** returns true if the SmartTag consumes this event. */
329 bool AnnotationTag::KeyInput( const KeyEvent& rKEvt )
331 if( !mxAnnotation.is() )
332 return false;
334 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
335 switch( nCode )
337 case KEY_DELETE:
338 mrManager.DeleteAnnotation( mxAnnotation );
339 return true;
341 case KEY_DOWN:
342 case KEY_UP:
343 case KEY_LEFT:
344 case KEY_RIGHT:
345 return OnMove( rKEvt );
347 case KEY_ESCAPE:
349 SmartTagReference xThis( this );
350 mrView.getSmartTags().deselect();
351 return true;
354 case KEY_TAB:
355 mrManager.SelectNextAnnotation(!rKEvt.GetKeyCode().IsShift());
356 return true;
358 case KEY_RETURN:
359 case KEY_SPACE:
360 OpenPopup( true );
361 return true;
363 default:
364 return false;
368 /** returns true if the SmartTag consumes this event. */
369 bool AnnotationTag::Command( const CommandEvent& rCEvt )
371 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
372 return false;
373 if (vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow())
375 ::tools::Rectangle aContextRect(rCEvt.GetMousePosPixel(),Size(1,1));
376 weld::Window* pParent = weld::GetPopupParent(*pWindow, aContextRect);
377 mrManager.ExecuteAnnotationTagContextMenu(mxAnnotation, pParent, aContextRect);
378 return true;
380 return false;
383 void AnnotationTag::Move( int nDX, int nDY )
385 if( !mxAnnotation.is() )
386 return;
388 if( mrManager.GetDoc()->IsUndoEnabled() )
389 mrManager.GetDoc()->BegUndo( SdResId( STR_ANNOTATION_UNDO_MOVE ) );
391 RealPoint2D aPosition( mxAnnotation->getPosition() );
392 aPosition.X += static_cast<double>(nDX) / 100.0;
393 aPosition.Y += static_cast<double>(nDY) / 100.0;
394 mxAnnotation->setPosition( aPosition );
396 if( mrManager.GetDoc()->IsUndoEnabled() )
397 mrManager.GetDoc()->EndUndo();
399 mrView.updateHandles();
402 bool AnnotationTag::OnMove( const KeyEvent& rKEvt )
404 ::tools::Long nX = 0;
405 ::tools::Long nY = 0;
407 switch( rKEvt.GetKeyCode().GetCode() )
409 case KEY_UP: nY = -1; break;
410 case KEY_DOWN: nY = 1; break;
411 case KEY_LEFT: nX = -1; break;
412 case KEY_RIGHT: nX = 1; break;
413 default: break;
416 if(rKEvt.GetKeyCode().IsMod2())
418 OutputDevice* pOut = mrView.GetViewShell()->GetActiveWindow()->GetOutDev();
419 Size aLogicSizeOnePixel = pOut ? pOut->PixelToLogic(Size(1,1)) : Size(100, 100);
420 nX *= aLogicSizeOnePixel.Width();
421 nY *= aLogicSizeOnePixel.Height();
423 else
425 // old, fixed move distance
426 nX *= 100;
427 nY *= 100;
430 if( nX || nY )
432 // move the annotation
433 Move( nX, nY );
436 return true;
439 void AnnotationTag::CheckPossibilities()
443 sal_Int32 AnnotationTag::GetMarkablePointCount() const
445 return 0;
448 sal_Int32 AnnotationTag::GetMarkedPointCount() const
450 return 0;
453 bool AnnotationTag::MarkPoint(SdrHdl& /*rHdl*/, bool /*bUnmark*/ )
455 return false;
458 bool AnnotationTag::MarkPoints(const ::tools::Rectangle* /*pRect*/, bool /*bUnmark*/ )
460 return false;
463 bool AnnotationTag::getContext( SdrViewContext& /*rContext*/ )
465 return false;
468 void AnnotationTag::addCustomHandles( SdrHdlList& rHandlerList )
470 if( !mxAnnotation.is() )
471 return;
473 SmartTagReference xThis( this );
474 std::unique_ptr<AnnotationHdl> pHdl(new AnnotationHdl( xThis, mxAnnotation, Point() ));
475 pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM );
476 pHdl->SetPageView( mrView.GetSdrPageView() );
478 RealPoint2D aPosition( mxAnnotation->getPosition() );
479 Point aBasePos( static_cast<::tools::Long>(aPosition.X * 100.0), static_cast<::tools::Long>(aPosition.Y * 100.0) );
480 pHdl->SetPos( aBasePos );
482 rHandlerList.AddHdl( std::move(pHdl) );
485 void AnnotationTag::disposing()
487 if( mpListenWindow )
489 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
492 mxAnnotation.clear();
493 ClosePopup();
494 SmartTag::disposing();
497 void AnnotationTag::select()
499 SmartTag::select();
501 mrManager.onTagSelected( *this );
503 vcl::Window* pWindow = mrView.GetViewShell()->GetActiveWindow();
504 if( pWindow )
506 RealPoint2D aPosition( mxAnnotation->getPosition() );
507 Point aPos( static_cast<::tools::Long>(aPosition.X * 100.0), static_cast<::tools::Long>(aPosition.Y * 100.0) );
509 ::tools::Rectangle aVisRect( aPos, pWindow->PixelToLogic(maSize) );
510 mrView.MakeVisible(aVisRect, *pWindow);
514 void AnnotationTag::deselect()
516 SmartTag::deselect();
518 ClosePopup();
520 mrManager.onTagDeselected( *this );
523 BitmapEx AnnotationTag::CreateAnnotationBitmap( bool bSelected )
525 ScopedVclPtrInstance< VirtualDevice > pVDev;
527 OUString sText;
528 auto* pAnnotation = dynamic_cast<sd::Annotation*>(mxAnnotation.get());
529 if (pAnnotation && pAnnotation->isFreeText())
531 sText = mxAnnotation->getTextRange()->getString();
533 else
535 OUString sInitials(mxAnnotation->getInitials());
536 if (sInitials.isEmpty())
538 sInitials = getInitials(mxAnnotation->getAuthor());
541 sText = sInitials + " " + OUString::number(mnIndex);
544 pVDev->SetFont( mrFont );
546 const int BORDER_X = 4; // pixels
547 const int BORDER_Y = 4; // pixels
549 maSize = Size(pVDev->GetTextWidth(sText) + 2 * BORDER_X, pVDev->GetTextHeight() + 2 * BORDER_Y);
550 pVDev->SetOutputSizePixel( maSize, false );
552 Color aBorderColor( maColor );
554 if( bSelected )
556 aBorderColor.Invert();
558 else
560 if( maColor.IsDark() )
562 aBorderColor.IncreaseLuminance( 32 );
564 else
566 aBorderColor.DecreaseLuminance( 32 );
570 Point aPos;
571 ::tools::Rectangle aBorderRect( aPos, maSize );
572 pVDev->SetLineColor(aBorderColor);
573 pVDev->SetFillColor(maColor);
574 pVDev->DrawRect( aBorderRect );
576 pVDev->SetTextColor( maColor.IsDark() ? COL_WHITE : COL_BLACK );
577 pVDev->DrawText(Point(BORDER_X, BORDER_Y), sText);
579 return pVDev->GetBitmapEx( aPos, maSize );
582 void AnnotationTag::OpenPopup( bool bEdit )
584 if( !mxAnnotation.is() )
585 return;
587 if( !mpAnnotationWindow )
589 OutputDevice* pOut = getView().GetFirstOutputDevice();
590 vcl::Window* pWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
591 if( pWindow )
593 RealPoint2D aPosition( mxAnnotation->getPosition() );
594 Point aPos(pWindow->LogicToPixel( Point( static_cast<::tools::Long>(aPosition.X * 100.0), static_cast<::tools::Long>(aPosition.Y * 100.0) ) ) );
596 aPos.AdjustX(4 ); // magic!
597 aPos.AdjustY(1 );
599 ::tools::Rectangle aRect( aPos, maSize );
601 weld::Window* pParent = weld::GetPopupParent(*pWindow, aRect);
602 mpAnnotationWindow.reset(new AnnotationWindow(pParent, aRect, mrView.GetDocSh(), mxAnnotation));
603 mpAnnotationWindow->connect_closed(LINK(this, AnnotationTag, PopupModeEndHdl));
607 if (bEdit && mpAnnotationWindow)
608 mpAnnotationWindow->StartEdit();
611 IMPL_LINK_NOARG(AnnotationTag, PopupModeEndHdl, weld::Popover&, void)
613 ClosePopup();
616 void AnnotationTag::ClosePopup()
618 if (mpAnnotationWindow)
620 mpAnnotationWindow->SaveToDocument();
621 mpAnnotationWindow.reset();
625 IMPL_LINK(AnnotationTag, WindowEventHandler, VclWindowEvent&, rEvent, void)
627 vcl::Window* pWindow = rEvent.GetWindow();
629 if( !pWindow )
630 return;
632 if( pWindow != mpListenWindow )
633 return;
635 switch( rEvent.GetId() )
637 case VclEventId::WindowMouseButtonUp:
639 // if we stop pressing the button without a mouse move we open the popup
640 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
641 mpListenWindow = nullptr;
642 if( !mpAnnotationWindow )
643 OpenPopup(false);
645 break;
646 case VclEventId::WindowMouseMove:
648 // if we move the mouse after a button down we want to start dragging
649 mpListenWindow->RemoveEventListener( LINK(this, AnnotationTag, WindowEventHandler));
650 mpListenWindow = nullptr;
652 SdrHdl* pHdl = mrView.PickHandle(maMouseDownPos);
653 if( pHdl )
655 mrView.BrkAction();
656 const sal_uInt16 nDrgLog = static_cast<sal_uInt16>(pWindow->PixelToLogic(Size(DRGPIX,0)).Width());
658 rtl::Reference< AnnotationTag > xTag( this );
660 SdrDragMethod* pDragMethod = new AnnotationDragMove( mrView, xTag );
661 mrView.BegDragObj(maMouseDownPos, nullptr, pHdl, nDrgLog, pDragMethod );
664 break;
665 case VclEventId::ObjectDying:
666 mpListenWindow = nullptr;
667 break;
668 default: break;
672 } // end of namespace sd
674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */