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 <comphelper/processfactory.hxx>
21 #include <comphelper/diagnose_ex.hxx>
22 #include <com/sun/star/awt/MouseButton.hpp>
23 #include <com/sun/star/awt/SystemPointer.hpp>
24 #include <com/sun/star/system/SystemShellExecute.hpp>
25 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
26 #include <com/sun/star/system/XSystemShellExecute.hpp>
27 #include <svx/ImageMapInfo.hxx>
29 #include "shapemanagerimpl.hxx"
35 using namespace css::uno
;
36 using namespace css::drawing
;
37 using namespace css::system
;
39 namespace slideshow::internal
{
41 ShapeManagerImpl::ShapeManagerImpl( EventMultiplexer
& rMultiplexer
,
42 LayerManagerSharedPtr xLayerManager
,
43 CursorManager
& rCursorManager
,
44 const ShapeEventListenerMap
& rGlobalListenersMap
,
45 const ShapeCursorMap
& rGlobalCursorMap
,
46 const Reference
<XDrawPage
>& xDrawPage
):
47 mrMultiplexer(rMultiplexer
),
48 mpLayerManager(std::move(xLayerManager
)),
49 mrCursorManager(rCursorManager
),
50 mrGlobalListenersMap(rGlobalListenersMap
),
51 mrGlobalCursorMap(rGlobalCursorMap
),
60 void ShapeManagerImpl::activate()
67 // register this handler on EventMultiplexer.
68 // Higher prio (overrides other engine handlers)
69 mrMultiplexer
.addMouseMoveHandler( shared_from_this(), 2.0 );
70 mrMultiplexer
.addClickHandler( shared_from_this(), 2.0 );
71 mrMultiplexer
.addShapeListenerHandler( shared_from_this() );
74 for( const auto& rListener
: mrGlobalListenersMap
)
75 listenerAdded( rListener
.first
);
78 for( const auto& rListener
: mrGlobalCursorMap
)
79 cursorChanged( rListener
.first
, rListener
.second
);
82 mpLayerManager
->activate();
85 void ShapeManagerImpl::deactivate()
93 mpLayerManager
->deactivate();
95 maShapeListenerMap
.clear();
96 maShapeCursorMap
.clear();
98 mrMultiplexer
.removeShapeListenerHandler( shared_from_this() );
99 mrMultiplexer
.removeMouseMoveHandler( shared_from_this() );
100 mrMultiplexer
.removeClickHandler( shared_from_this() );
103 void ShapeManagerImpl::dispose()
105 // remove listeners (EventMultiplexer holds shared_ptr on us)
108 maHyperlinkShapes
.clear();
109 maShapeCursorMap
.clear();
110 maShapeListenerMap
.clear();
111 mpLayerManager
.reset();
114 bool ShapeManagerImpl::handleMousePressed( awt::MouseEvent
const& )
117 return false; // did not handle the event
120 bool ShapeManagerImpl::handleMouseReleased( awt::MouseEvent
const& e
)
122 if( !mbEnabled
|| e
.Buttons
!= awt::MouseButton::LEFT
)
125 basegfx::B2DPoint
const aPosition( e
.X
, e
.Y
);
127 // first check for hyperlinks, because these have
129 OUString
const hyperlink( checkForHyperlink(aPosition
) );
130 if( !hyperlink
.isEmpty() )
132 mrMultiplexer
.notifyHyperlinkClicked(hyperlink
);
133 return true; // event consumed
136 // tdf#74045 Handle ImageMaps
137 OUString
const imageMapLink(checkForImageMap(e
));
138 if (!imageMapLink
.isEmpty())
140 Reference
<XSystemShellExecute
> exec(
141 SystemShellExecute::create(comphelper::getProcessComponentContext()));
142 exec
->execute(imageMapLink
, OUString(), SystemShellExecuteFlags::URIS_ONLY
);
147 // find matching shape (scan reversely, to coarsely match
149 auto aCurrBroadcaster
= std::find_if(maShapeListenerMap
.rbegin(), maShapeListenerMap
.rend(),
150 [&aPosition
](const ShapeToListenersMap::value_type
& rBroadcaster
) {
151 // TODO(F2): Get proper geometry polygon from the
152 // shape, to avoid having areas outside the shape
153 // react on the mouse
154 return rBroadcaster
.first
->getBounds().isInside( aPosition
)
155 && rBroadcaster
.first
->isVisible();
157 if (aCurrBroadcaster
!= maShapeListenerMap
.rend())
159 // shape hit, and shape is visible. Raise
162 std::shared_ptr
<comphelper::OInterfaceContainerHelper3
<css::presentation::XShapeEventListener
>> const & pCont
=
163 aCurrBroadcaster
->second
;
164 uno::Reference
<drawing::XShape
> const xShape(
165 aCurrBroadcaster
->first
->getXShape() );
167 // DON'T do anything with /this/ after this point!
169 [&xShape
, &e
]( const uno::Reference
< presentation::XShapeEventListener
>& rListener
)
170 { return rListener
->click( xShape
, e
); } );
172 return true; // handled this event
175 return false; // did not handle this event
178 bool ShapeManagerImpl::handleMouseDragged( const awt::MouseEvent
& )
181 return false; // did not handle the event
184 bool ShapeManagerImpl::handleMouseMoved( const awt::MouseEvent
& e
)
189 // find hit shape in map
190 const ::basegfx::B2DPoint
aPosition( e
.X
, e
.Y
);
191 sal_Int16
nNewCursor(-1);
193 if( !checkForHyperlink(aPosition
).isEmpty() || !checkForImageMap(e
).isEmpty() )
195 nNewCursor
= awt::SystemPointer::REFHAND
;
199 // find matching shape (scan reversely, to coarsely match
201 auto aCurrCursor
= std::find_if(maShapeCursorMap
.rbegin(), maShapeCursorMap
.rend(),
202 [&aPosition
](const ShapeToCursorMap::value_type
& rCursor
) {
203 // TODO(F2): Get proper geometry polygon from the
204 // shape, to avoid having areas outside the shape
205 // react on the mouse
206 return rCursor
.first
->getBounds().isInside( aPosition
)
207 && rCursor
.first
->isVisible();
209 if (aCurrCursor
!= maShapeCursorMap
.rend())
211 // shape found, and it's visible. set
212 // requested cursor to shape's
213 nNewCursor
= aCurrCursor
->second
;
217 if( nNewCursor
== -1 )
218 mrCursorManager
.resetCursor();
220 mrCursorManager
.requestCursor( nNewCursor
);
222 return false; // we don't /eat/ this event. Lower prio
223 // handler should see it, too.
226 bool ShapeManagerImpl::update()
228 if( mbEnabled
&& mpLayerManager
)
229 return mpLayerManager
->update();
234 bool ShapeManagerImpl::needsUpdate() const
236 if( mbEnabled
&& mpLayerManager
)
237 return mpLayerManager
->isUpdatePending();
242 void ShapeManagerImpl::enterAnimationMode( const AnimatableShapeSharedPtr
& rShape
)
244 if( mbEnabled
&& mpLayerManager
)
245 mpLayerManager
->enterAnimationMode(rShape
);
248 void ShapeManagerImpl::leaveAnimationMode( const AnimatableShapeSharedPtr
& rShape
)
250 if( mbEnabled
&& mpLayerManager
)
251 mpLayerManager
->leaveAnimationMode(rShape
);
254 void ShapeManagerImpl::notifyShapeUpdate( const ShapeSharedPtr
& rShape
)
256 if( mbEnabled
&& mpLayerManager
)
257 mpLayerManager
->notifyShapeUpdate(rShape
);
260 ShapeSharedPtr
ShapeManagerImpl::lookupShape( uno::Reference
< drawing::XShape
> const & xShape
) const
263 return mpLayerManager
->lookupShape(xShape
);
265 return ShapeSharedPtr();
268 const XShapeToShapeMap
& ShapeManagerImpl::getXShapeToShapeMap() const
270 assert( mpLayerManager
);
271 return mpLayerManager
->getXShapeToShapeMap();
274 void ShapeManagerImpl::addHyperlinkArea( const HyperlinkAreaSharedPtr
& rArea
)
276 maHyperlinkShapes
.insert(rArea
);
279 AttributableShapeSharedPtr
ShapeManagerImpl::getSubsetShape( const AttributableShapeSharedPtr
& rOrigShape
,
280 const DocTreeNode
& rTreeNode
)
283 return mpLayerManager
->getSubsetShape(rOrigShape
,rTreeNode
);
285 return AttributableShapeSharedPtr();
288 void ShapeManagerImpl::revokeSubset( const AttributableShapeSharedPtr
& rOrigShape
,
289 const AttributableShapeSharedPtr
& rSubsetShape
)
292 mpLayerManager
->revokeSubset(rOrigShape
,rSubsetShape
);
295 bool ShapeManagerImpl::listenerAdded(
296 const uno::Reference
<drawing::XShape
>& xShape
)
298 ShapeEventListenerMap::const_iterator aIter
= mrGlobalListenersMap
.find( xShape
);
299 if( aIter
== mrGlobalListenersMap
.end() )
301 ENSURE_OR_RETURN_FALSE(false,
302 "ShapeManagerImpl::listenerAdded(): global "
303 "shape listener map inconsistency!");
306 // is this one of our shapes? other shapes are ignored.
307 ShapeSharedPtr
pShape( lookupShape(xShape
) );
310 maShapeListenerMap
.emplace(pShape
, aIter
->second
);
316 bool ShapeManagerImpl::listenerRemoved( const uno::Reference
<drawing::XShape
>& xShape
)
318 // shape really erased from map? maybe there are other listeners
319 // for the same shape pending...
320 if( mrGlobalListenersMap
.find(xShape
) == mrGlobalListenersMap
.end() )
322 // is this one of our shapes? other shapes are ignored.
323 ShapeSharedPtr
pShape( lookupShape(xShape
) );
325 maShapeListenerMap
.erase(pShape
);
331 void ShapeManagerImpl::cursorChanged( const uno::Reference
<drawing::XShape
>& xShape
,
334 ShapeSharedPtr
pShape( lookupShape(xShape
) );
336 // is this one of our shapes? other shapes are ignored.
340 if( mrGlobalCursorMap
.find(xShape
) == mrGlobalCursorMap
.end() )
342 // erased from global map - erase locally, too
343 maShapeCursorMap
.erase(pShape
);
347 // included in global map - update local one
348 ShapeToCursorMap::iterator aIter
;
349 if( (aIter
= maShapeCursorMap
.find(pShape
))
350 == maShapeCursorMap
.end() )
352 maShapeCursorMap
.emplace(pShape
, nCursor
);
356 aIter
->second
= nCursor
;
361 OUString
ShapeManagerImpl::checkForHyperlink( basegfx::B2DPoint
const& hitPos
) const
363 // find matching region (scan reversely, to coarsely match
364 // paint order): set is ordered by priority
365 AreaSet::const_reverse_iterator
iPos( maHyperlinkShapes
.rbegin() );
366 AreaSet::const_reverse_iterator
const iEnd( maHyperlinkShapes
.rend() );
367 for( ; iPos
!= iEnd
; ++iPos
)
369 HyperlinkAreaSharedPtr
const& pArea
= *iPos
;
371 HyperlinkArea::HyperlinkRegions
const linkRegions(
372 pArea
->getHyperlinkRegions() );
374 for( std::size_t i
= linkRegions
.size(); i
--; )
376 basegfx::B2DRange
const& region
= linkRegions
[i
].first
;
377 if( region
.isInside(hitPos
) )
378 return linkRegions
[i
].second
;
385 OUString
ShapeManagerImpl::checkForImageMap( awt::MouseEvent
const& evt
) const
387 for (sal_Int32 i
= 0; i
< mxDrawPage
->getCount(); i
++)
389 Reference
<XShape
> xShape(mxDrawPage
->getByIndex(i
), UNO_QUERY_THROW
);
390 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(xShape
);
393 const IMapObject
* pIMapObj
= SvxIMapInfo::GetHitIMapObject(pObj
, Point(evt
.X
, evt
.Y
));
394 if (pIMapObj
&& !pIMapObj
->GetURL().isEmpty())
396 return pIMapObj
->GetURL();
402 void ShapeManagerImpl::addIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr
& rHandler
)
404 maIntrinsicAnimationEventHandlers
.add( rHandler
);
407 void ShapeManagerImpl::removeIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr
& rHandler
)
409 maIntrinsicAnimationEventHandlers
.remove( rHandler
);
412 void ShapeManagerImpl::notifyIntrinsicAnimationsEnabled()
414 maIntrinsicAnimationEventHandlers
.applyAll(
415 std::mem_fn(&IntrinsicAnimationEventHandler::enableAnimations
));
418 void ShapeManagerImpl::notifyIntrinsicAnimationsDisabled()
420 maIntrinsicAnimationEventHandlers
.applyAll(
421 std::mem_fn(&IntrinsicAnimationEventHandler::disableAnimations
));
425 } // namespace slideshow::internal
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */