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