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