Branch data 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: */
|