Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / slideshow / source / engine / slide / shapemanagerimpl.cxx
blobce69997529e22ea97ff5975ff883e2ec4836d661
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 <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"
31 #include <functional>
32 #include <utility>
34 using namespace css;
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),
52 maShapeListenerMap(),
53 maShapeCursorMap(),
54 maHyperlinkShapes(),
55 mbEnabled(false),
56 mxDrawPage(xDrawPage)
60 void ShapeManagerImpl::activate()
62 if( mbEnabled )
63 return;
65 mbEnabled = true;
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() );
73 // clone listener map
74 for( const auto& rListener : mrGlobalListenersMap )
75 listenerAdded( rListener.first );
77 // clone cursor map
78 for( const auto& rListener : mrGlobalCursorMap )
79 cursorChanged( rListener.first, rListener.second );
81 if( mpLayerManager )
82 mpLayerManager->activate();
85 void ShapeManagerImpl::deactivate()
87 if( !mbEnabled )
88 return;
90 mbEnabled = false;
92 if( mpLayerManager )
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)
106 deactivate();
108 maHyperlinkShapes.clear();
109 maShapeCursorMap.clear();
110 maShapeListenerMap.clear();
111 mpLayerManager.reset();
114 bool ShapeManagerImpl::handleMousePressed( awt::MouseEvent const& )
116 // not used here
117 return false; // did not handle the event
120 bool ShapeManagerImpl::handleMouseReleased( awt::MouseEvent const& e )
122 if( !mbEnabled || e.Buttons != awt::MouseButton::LEFT)
123 return false;
125 basegfx::B2DPoint const aPosition( e.X, e.Y );
127 // first check for hyperlinks, because these have
128 // highest prio:
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);
144 return true;
147 // find matching shape (scan reversely, to coarsely match
148 // paint order)
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
160 // event.
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!
168 pCont->forEach(
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& )
180 // not used here
181 return false; // did not handle the event
184 bool ShapeManagerImpl::handleMouseMoved( const awt::MouseEvent& e )
186 if( !mbEnabled )
187 return false;
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;
197 else
199 // find matching shape (scan reversely, to coarsely match
200 // paint order)
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();
219 else
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();
231 return false;
234 bool ShapeManagerImpl::needsUpdate() const
236 if( mbEnabled && mpLayerManager )
237 return mpLayerManager->isUpdatePending();
239 return false;
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
262 if( mpLayerManager )
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 )
282 if( mpLayerManager )
283 return mpLayerManager->getSubsetShape(rOrigShape,rTreeNode);
285 return AttributableShapeSharedPtr();
288 void ShapeManagerImpl::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
289 const AttributableShapeSharedPtr& rSubsetShape )
291 if( mpLayerManager )
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) );
308 if( pShape )
310 maShapeListenerMap.emplace(pShape, aIter->second);
313 return true;
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) );
324 if( pShape )
325 maShapeListenerMap.erase(pShape);
328 return true;
331 void ShapeManagerImpl::cursorChanged( const uno::Reference<drawing::XShape>& xShape,
332 sal_Int16 nCursor )
334 ShapeSharedPtr pShape( lookupShape(xShape) );
336 // is this one of our shapes? other shapes are ignored.
337 if( !pShape )
338 return;
340 if( mrGlobalCursorMap.find(xShape) == mrGlobalCursorMap.end() )
342 // erased from global map - erase locally, too
343 maShapeCursorMap.erase(pShape);
345 else
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);
354 else
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;
382 return OUString();
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);
391 if (!pObj)
392 continue;
393 const IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(pObj, Point(evt.X, evt.Y));
394 if (pIMapObj && !pIMapObj->GetURL().isEmpty())
396 return pIMapObj->GetURL();
399 return OUString();
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: */