Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <canvas/debug.hxx>
22 : #include <tools/diagnose_ex.h>
23 : #include <com/sun/star/awt/MouseButton.hpp>
24 : #include <com/sun/star/awt/SystemPointer.hpp>
25 : #include <com/sun/star/presentation/XShapeEventListener.hpp>
26 : #include <com/sun/star/presentation/XSlideShowListener.hpp>
27 : #include <com/sun/star/awt/MouseButton.hpp>
28 :
29 : #include "shapemanagerimpl.hxx"
30 :
31 : #include <boost/bind.hpp>
32 :
33 : #include <o3tl/compat_functional.hxx>
34 :
35 : using namespace com::sun::star;
36 :
37 : namespace slideshow {
38 : namespace internal {
39 :
40 0 : ShapeManagerImpl::ShapeManagerImpl( EventMultiplexer& rMultiplexer,
41 : LayerManagerSharedPtr const& rLayerManager,
42 : CursorManager& rCursorManager,
43 : const ShapeEventListenerMap& rGlobalListenersMap,
44 : const ShapeCursorMap& rGlobalCursorMap ):
45 : mrMultiplexer(rMultiplexer),
46 : mpLayerManager(rLayerManager),
47 : mrCursorManager(rCursorManager),
48 : mrGlobalListenersMap(rGlobalListenersMap),
49 : mrGlobalCursorMap(rGlobalCursorMap),
50 : maShapeListenerMap(),
51 : maShapeCursorMap(),
52 : maHyperlinkShapes(),
53 0 : mbEnabled(false)
54 : {
55 0 : }
56 :
57 0 : void ShapeManagerImpl::activate( bool bSlideBackgoundPainted )
58 : {
59 0 : if( !mbEnabled )
60 : {
61 0 : mbEnabled = true;
62 :
63 : // register this handler on EventMultiplexer.
64 : // Higher prio (overrides other engine handlers)
65 0 : mrMultiplexer.addMouseMoveHandler( shared_from_this(), 2.0 );
66 0 : mrMultiplexer.addClickHandler( shared_from_this(), 2.0 );
67 0 : mrMultiplexer.addShapeListenerHandler( shared_from_this() );
68 :
69 : // clone listener map
70 0 : uno::Reference<presentation::XShapeEventListener> xDummyListener;
71 : std::for_each( mrGlobalListenersMap.begin(),
72 : mrGlobalListenersMap.end(),
73 : boost::bind( &ShapeManagerImpl::listenerAdded,
74 : this,
75 : boost::cref(xDummyListener),
76 : boost::bind(
77 : o3tl::select1st<ShapeEventListenerMap::value_type>(),
78 0 : _1 )));
79 :
80 : // clone cursor map
81 : std::for_each( mrGlobalCursorMap.begin(),
82 : mrGlobalCursorMap.end(),
83 : boost::bind( &ShapeManagerImpl::cursorChanged,
84 : this,
85 : boost::bind(
86 : o3tl::select1st<ShapeCursorMap::value_type>(),
87 : _1 ),
88 : boost::bind(
89 : o3tl::select2nd<ShapeCursorMap::value_type>(),
90 0 : _1 )));
91 :
92 0 : if( mpLayerManager )
93 0 : mpLayerManager->activate( bSlideBackgoundPainted );
94 : }
95 0 : }
96 :
97 0 : void ShapeManagerImpl::deactivate()
98 : {
99 0 : if( mbEnabled )
100 : {
101 0 : mbEnabled = false;
102 :
103 0 : if( mpLayerManager )
104 0 : mpLayerManager->deactivate();
105 :
106 0 : maShapeListenerMap.clear();
107 0 : maShapeCursorMap.clear();
108 :
109 0 : mrMultiplexer.removeShapeListenerHandler( shared_from_this() );
110 0 : mrMultiplexer.removeMouseMoveHandler( shared_from_this() );
111 0 : mrMultiplexer.removeClickHandler( shared_from_this() );
112 : }
113 0 : }
114 :
115 0 : void ShapeManagerImpl::dispose()
116 : {
117 : // remove listeners (EventMultiplexer holds shared_ptr on us)
118 0 : deactivate();
119 :
120 0 : maHyperlinkShapes.clear();
121 0 : maShapeCursorMap.clear();
122 0 : maShapeListenerMap.clear();
123 0 : mpLayerManager.reset();
124 0 : }
125 :
126 0 : bool ShapeManagerImpl::handleMousePressed( awt::MouseEvent const& )
127 : {
128 : // not used here
129 0 : return false; // did not handle the event
130 : }
131 :
132 0 : bool ShapeManagerImpl::handleMouseReleased( awt::MouseEvent const& e )
133 : {
134 0 : if( !mbEnabled || e.Buttons != awt::MouseButton::LEFT)
135 0 : return false;
136 :
137 0 : basegfx::B2DPoint const aPosition( e.X, e.Y );
138 :
139 : // first check for hyperlinks, because these have
140 : // highest prio:
141 0 : rtl::OUString const hyperlink( checkForHyperlink(aPosition) );
142 0 : if( !hyperlink.isEmpty() )
143 : {
144 0 : mrMultiplexer.notifyHyperlinkClicked(hyperlink);
145 0 : return true; // event consumed
146 : }
147 :
148 : // find matching shape (scan reversely, to coarsely match
149 : // paint order)
150 : ShapeToListenersMap::reverse_iterator aCurrBroadcaster(
151 0 : maShapeListenerMap.rbegin() );
152 : ShapeToListenersMap::reverse_iterator const aEndBroadcasters(
153 0 : maShapeListenerMap.rend() );
154 0 : while( aCurrBroadcaster != aEndBroadcasters )
155 : {
156 : // TODO(F2): Get proper geometry polygon from the
157 : // shape, to avoid having areas outside the shape
158 : // react on the mouse
159 0 : if( aCurrBroadcaster->first->getBounds().isInside( aPosition ) &&
160 0 : aCurrBroadcaster->first->isVisible() )
161 : {
162 : // shape hit, and shape is visible. Raise
163 : // event.
164 :
165 : boost::shared_ptr<cppu::OInterfaceContainerHelper> const pCont(
166 0 : aCurrBroadcaster->second );
167 : uno::Reference<drawing::XShape> const xShape(
168 0 : aCurrBroadcaster->first->getXShape() );
169 :
170 : // DON'T do anything with /this/ after this point!
171 : pCont->forEach<presentation::XShapeEventListener>(
172 : boost::bind( &presentation::XShapeEventListener::click,
173 : _1,
174 : boost::cref(xShape),
175 0 : boost::cref(e) ));
176 :
177 0 : return true; // handled this event
178 : }
179 :
180 0 : ++aCurrBroadcaster;
181 : }
182 :
183 0 : return false; // did not handle this event
184 : }
185 :
186 0 : bool ShapeManagerImpl::handleMouseEntered( const awt::MouseEvent& )
187 : {
188 : // not used here
189 0 : return false; // did not handle the event
190 : }
191 :
192 0 : bool ShapeManagerImpl::handleMouseExited( const awt::MouseEvent& )
193 : {
194 : // not used here
195 0 : return false; // did not handle the event
196 : }
197 :
198 0 : bool ShapeManagerImpl::handleMouseDragged( const awt::MouseEvent& )
199 : {
200 : // not used here
201 0 : return false; // did not handle the event
202 : }
203 :
204 0 : bool ShapeManagerImpl::handleMouseMoved( const awt::MouseEvent& e )
205 : {
206 0 : if( !mbEnabled )
207 0 : return false;
208 :
209 : // find hit shape in map
210 0 : const ::basegfx::B2DPoint aPosition( e.X, e.Y );
211 0 : sal_Int16 nNewCursor(-1);
212 :
213 0 : if( !checkForHyperlink(aPosition).isEmpty() )
214 : {
215 0 : nNewCursor = awt::SystemPointer::REFHAND;
216 : }
217 : else
218 : {
219 : // find matching shape (scan reversely, to coarsely match
220 : // paint order)
221 : ShapeToCursorMap::reverse_iterator aCurrCursor(
222 0 : maShapeCursorMap.rbegin() );
223 : ShapeToCursorMap::reverse_iterator const aEndCursors(
224 0 : maShapeCursorMap.rend() );
225 0 : while( aCurrCursor != aEndCursors )
226 : {
227 : // TODO(F2): Get proper geometry polygon from the
228 : // shape, to avoid having areas outside the shape
229 : // react on the mouse
230 0 : if( aCurrCursor->first->getBounds().isInside( aPosition ) &&
231 0 : aCurrCursor->first->isVisible() )
232 : {
233 : // shape found, and it's visible. set
234 : // requested cursor to shape's
235 0 : nNewCursor = aCurrCursor->second;
236 0 : break;
237 : }
238 :
239 0 : ++aCurrCursor;
240 : }
241 : }
242 :
243 0 : if( nNewCursor == -1 )
244 0 : mrCursorManager.resetCursor();
245 : else
246 0 : mrCursorManager.requestCursor( nNewCursor );
247 :
248 0 : return false; // we don't /eat/ this event. Lower prio
249 : // handler should see it, too.
250 : }
251 :
252 0 : bool ShapeManagerImpl::update()
253 : {
254 0 : if( mbEnabled && mpLayerManager )
255 0 : return mpLayerManager->update();
256 :
257 0 : return false;
258 : }
259 :
260 0 : bool ShapeManagerImpl::update( ViewSharedPtr const& /*rView*/ )
261 : {
262 : // am not doing view-specific updates here.
263 0 : return false;
264 : }
265 :
266 0 : bool ShapeManagerImpl::needsUpdate() const
267 : {
268 0 : if( mbEnabled && mpLayerManager )
269 0 : return mpLayerManager->isUpdatePending();
270 :
271 0 : return false;
272 : }
273 :
274 0 : void ShapeManagerImpl::enterAnimationMode( const AnimatableShapeSharedPtr& rShape )
275 : {
276 0 : if( mbEnabled && mpLayerManager )
277 0 : mpLayerManager->enterAnimationMode(rShape);
278 0 : }
279 :
280 0 : void ShapeManagerImpl::leaveAnimationMode( const AnimatableShapeSharedPtr& rShape )
281 : {
282 0 : if( mbEnabled && mpLayerManager )
283 0 : mpLayerManager->leaveAnimationMode(rShape);
284 0 : }
285 :
286 0 : void ShapeManagerImpl::notifyShapeUpdate( const ShapeSharedPtr& rShape )
287 : {
288 0 : if( mbEnabled && mpLayerManager )
289 0 : mpLayerManager->notifyShapeUpdate(rShape);
290 0 : }
291 :
292 0 : ShapeSharedPtr ShapeManagerImpl::lookupShape( uno::Reference< drawing::XShape > const & xShape ) const
293 : {
294 0 : if( mpLayerManager )
295 0 : return mpLayerManager->lookupShape(xShape);
296 :
297 0 : return ShapeSharedPtr();
298 : }
299 :
300 0 : void ShapeManagerImpl::addHyperlinkArea( const HyperlinkAreaSharedPtr& rArea )
301 : {
302 0 : maHyperlinkShapes.insert(rArea);
303 0 : }
304 :
305 0 : void ShapeManagerImpl::removeHyperlinkArea( const HyperlinkAreaSharedPtr& rArea )
306 : {
307 0 : maHyperlinkShapes.erase(rArea);
308 0 : }
309 :
310 0 : AttributableShapeSharedPtr ShapeManagerImpl::getSubsetShape( const AttributableShapeSharedPtr& rOrigShape,
311 : const DocTreeNode& rTreeNode )
312 : {
313 0 : if( mpLayerManager )
314 0 : return mpLayerManager->getSubsetShape(rOrigShape,rTreeNode);
315 :
316 0 : return AttributableShapeSharedPtr();
317 : }
318 :
319 0 : void ShapeManagerImpl::revokeSubset( const AttributableShapeSharedPtr& rOrigShape,
320 : const AttributableShapeSharedPtr& rSubsetShape )
321 : {
322 0 : if( mpLayerManager )
323 0 : mpLayerManager->revokeSubset(rOrigShape,rSubsetShape);
324 0 : }
325 :
326 0 : bool ShapeManagerImpl::listenerAdded(
327 : const uno::Reference<presentation::XShapeEventListener>& /*xListener*/,
328 : const uno::Reference<drawing::XShape>& xShape )
329 : {
330 0 : ShapeEventListenerMap::const_iterator aIter;
331 0 : if( (aIter = mrGlobalListenersMap.find( xShape )) ==
332 0 : mrGlobalListenersMap.end() )
333 : {
334 0 : ENSURE_OR_RETURN_FALSE(false,
335 : "ShapeManagerImpl::listenerAdded(): global "
336 : "shape listener map inconsistency!");
337 : }
338 :
339 : // is this one of our shapes? other shapes are ignored.
340 0 : ShapeSharedPtr pShape( lookupShape(xShape) );
341 0 : if( pShape )
342 : {
343 : maShapeListenerMap.insert(
344 : ShapeToListenersMap::value_type(
345 : pShape,
346 0 : aIter->second));
347 : }
348 :
349 0 : return true;
350 : }
351 :
352 0 : bool ShapeManagerImpl::listenerRemoved(
353 : const uno::Reference<presentation::XShapeEventListener>& /*xListener*/,
354 : const uno::Reference<drawing::XShape>& xShape )
355 : {
356 : // shape really erased from map? maybe there are other listeners
357 : // for the same shape pending...
358 0 : if( mrGlobalListenersMap.find(xShape) == mrGlobalListenersMap.end() )
359 : {
360 : // is this one of our shapes? other shapes are ignored.
361 0 : ShapeSharedPtr pShape( lookupShape(xShape) );
362 0 : if( pShape )
363 0 : maShapeListenerMap.erase(pShape);
364 : }
365 :
366 0 : return true;
367 : }
368 :
369 0 : bool ShapeManagerImpl::cursorChanged( const uno::Reference<drawing::XShape>& xShape,
370 : sal_Int16 nCursor )
371 : {
372 0 : ShapeSharedPtr pShape( lookupShape(xShape) );
373 :
374 : // is this one of our shapes? other shapes are ignored.
375 0 : if( !pShape )
376 0 : return false;
377 :
378 0 : if( mrGlobalCursorMap.find(xShape) == mrGlobalCursorMap.end() )
379 : {
380 : // erased from global map - erase locally, too
381 0 : maShapeCursorMap.erase(pShape);
382 : }
383 : else
384 : {
385 : // included in global map - update local one
386 0 : ShapeToCursorMap::iterator aIter;
387 0 : if( (aIter = maShapeCursorMap.find(pShape))
388 0 : == maShapeCursorMap.end() )
389 : {
390 : maShapeCursorMap.insert(
391 : ShapeToCursorMap::value_type(
392 : pShape,
393 0 : nCursor ));
394 : }
395 : else
396 : {
397 0 : aIter->second = nCursor;
398 : }
399 : }
400 :
401 0 : return true;
402 : }
403 :
404 0 : rtl::OUString ShapeManagerImpl::checkForHyperlink( basegfx::B2DPoint const& hitPos ) const
405 : {
406 : // find matching region (scan reversely, to coarsely match
407 : // paint order): set is ordered by priority
408 0 : AreaSet::const_reverse_iterator iPos( maHyperlinkShapes.rbegin() );
409 0 : AreaSet::const_reverse_iterator const iEnd( maHyperlinkShapes.rend() );
410 0 : for( ; iPos != iEnd; ++iPos )
411 : {
412 0 : HyperlinkAreaSharedPtr const& pArea = *iPos;
413 :
414 : HyperlinkArea::HyperlinkRegions const linkRegions(
415 0 : pArea->getHyperlinkRegions() );
416 :
417 0 : for( std::size_t i = linkRegions.size(); i--; )
418 : {
419 0 : basegfx::B2DRange const& region = linkRegions[i].first;
420 0 : if( region.isInside(hitPos) )
421 0 : return linkRegions[i].second;
422 : }
423 0 : }
424 :
425 0 : return rtl::OUString();
426 : }
427 :
428 0 : void ShapeManagerImpl::addIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler )
429 : {
430 0 : maIntrinsicAnimationEventHandlers.add( rHandler );
431 0 : }
432 :
433 0 : void ShapeManagerImpl::removeIntrinsicAnimationHandler( const IntrinsicAnimationEventHandlerSharedPtr& rHandler )
434 : {
435 0 : maIntrinsicAnimationEventHandlers.remove( rHandler );
436 0 : }
437 :
438 0 : bool ShapeManagerImpl::notifyIntrinsicAnimationsEnabled()
439 : {
440 : return maIntrinsicAnimationEventHandlers.applyAll(
441 0 : boost::mem_fn(&IntrinsicAnimationEventHandler::enableAnimations));
442 : }
443 :
444 0 : bool ShapeManagerImpl::notifyIntrinsicAnimationsDisabled()
445 : {
446 : return maIntrinsicAnimationEventHandlers.applyAll(
447 0 : boost::mem_fn(&IntrinsicAnimationEventHandler::disableAnimations));
448 : }
449 :
450 :
451 :
452 : } // namespace internal
453 0 : } // namespace presentation
454 :
455 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|