xref: /trunk/main/vcl/source/window/dndevdis.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <dndevdis.hxx>
32 #include <dndlcon.hxx>
33 #include <window.h>
34 #include <svdata.hxx>
35 
36 #include <vos/mutex.hxx>
37 #include <vcl/svapp.hxx>
38 
39 using namespace ::osl;
40 using namespace ::vos;
41 using namespace ::cppu;
42 using namespace ::com::sun::star::uno;
43 using namespace ::com::sun::star::lang;
44 using namespace ::com::sun::star::datatransfer;
45 using namespace ::com::sun::star::datatransfer::dnd;
46 
47 //==================================================================================================
48 // DNDEventDispatcher::DNDEventDispatcher
49 //==================================================================================================
50 
51 DNDEventDispatcher::DNDEventDispatcher( Window * pTopWindow ):
52 	m_pTopWindow( pTopWindow ),
53 	m_pCurrentWindow( NULL )
54 {
55 }
56 
57 //==================================================================================================
58 // DNDEventDispatcher::~DNDEventDispatcher
59 //==================================================================================================
60 
61 DNDEventDispatcher::~DNDEventDispatcher()
62 {
63 }
64 
65 //==================================================================================================
66 // DNDEventDispatcher::drop
67 //==================================================================================================
68 
69 void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde )
70 	throw(RuntimeException)
71 {
72 	MutexGuard aImplGuard( m_aMutex );
73 
74 	Point location( dtde.LocationX, dtde.LocationY );
75 
76 	// find the window that is toplevel for this coordinates
77 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
78 
79     // because those coordinates come from outside, they must be mirrored if RTL layout is active
80     if( Application::GetSettings().GetLayoutRTL() )
81         m_pTopWindow->ImplMirrorFramePos( location );
82     Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
83 
84 	if( NULL == pChildWindow )
85         pChildWindow = m_pTopWindow;
86 
87     while( pChildWindow->ImplGetClientWindow() )
88         pChildWindow = pChildWindow->ImplGetClientWindow();
89 
90     if( pChildWindow->ImplIsAntiparallel() )
91         pChildWindow->ImplReMirror( location );
92 
93 	aSolarGuard.clear();
94 
95 	// handle the case that drop is in an other vcl window than the last dragOver
96 	if( pChildWindow != m_pCurrentWindow )
97 	{
98 		// fire dragExit on listeners of previous window
99 		fireDragExitEvent( m_pCurrentWindow );
100 
101 		fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this),
102 			dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList );
103 	}
104 
105 	sal_Int32 nListeners = 0;
106 
107 	// send drop event to the child window
108 	nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction,
109 		location, dtde.SourceActions, dtde.Transferable );
110 
111 	// reject drop if no listeners found
112 	if( nListeners == 0 ) {
113 		OSL_TRACE( "rejecting drop due to missing listeners." );
114 		dtde.Context->rejectDrop();
115 	}
116 
117 	// this is a drop -> no further drag overs
118 	m_pCurrentWindow = NULL;
119 	m_aDataFlavorList.realloc( 0 );
120 }
121 
122 //==================================================================================================
123 // DNDEventDispatcher::dragEnter
124 //==================================================================================================
125 
126 void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee )
127 	throw(RuntimeException)
128 {
129 	MutexGuard aImplGuard( m_aMutex );
130 	Point location( dtdee.LocationX, dtdee.LocationY );
131 
132 	// find the window that is toplevel for this coordinates
133 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
134 
135     // because those coordinates come from outside, they must be mirrored if RTL layout is active
136     if( Application::GetSettings().GetLayoutRTL() )
137         m_pTopWindow->ImplMirrorFramePos( location );
138 	Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
139 
140 	if( NULL == pChildWindow )
141         pChildWindow = m_pTopWindow;
142 
143     while( pChildWindow->ImplGetClientWindow() )
144         pChildWindow = pChildWindow->ImplGetClientWindow();
145 
146     if( pChildWindow->ImplIsAntiparallel() )
147         pChildWindow->ImplReMirror( location );
148 
149 	aSolarGuard.clear();
150 
151 	// assume pointer write operation to be atomic
152 	m_pCurrentWindow = pChildWindow;
153 	m_aDataFlavorList = dtdee.SupportedDataFlavors;
154 
155 	// fire dragEnter on listeners of current window
156 	sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location,
157 		dtdee.SourceActions, dtdee.SupportedDataFlavors );
158 
159 	// reject drag if no listener found
160 	if( nListeners == 0 ) {
161 		OSL_TRACE( "rejecting drag enter due to missing listeners." );
162 		dtdee.Context->rejectDrag();
163 	}
164 
165 }
166 
167 //==================================================================================================
168 // DNDEventDispatcher::dragExit
169 //==================================================================================================
170 
171 void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ )
172 	throw(RuntimeException)
173 {
174 	MutexGuard aImplGuard( m_aMutex );
175 
176 	fireDragExitEvent( m_pCurrentWindow );
177 
178 	// reset member values
179 	m_pCurrentWindow = NULL;
180 	m_aDataFlavorList.realloc( 0 );
181 }
182 
183 //==================================================================================================
184 // DNDEventDispatcher::dragOver
185 //==================================================================================================
186 
187 void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde )
188 	throw(RuntimeException)
189 {
190 	MutexGuard aImplGuard( m_aMutex );
191 
192 	Point location( dtde.LocationX, dtde.LocationY );
193 	sal_Int32 nListeners;
194 
195 	// find the window that is toplevel for this coordinates
196 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
197 
198     // because those coordinates come from outside, they must be mirrored if RTL layout is active
199     if( Application::GetSettings().GetLayoutRTL() )
200         m_pTopWindow->ImplMirrorFramePos( location );
201 	Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
202 
203 	if( NULL == pChildWindow )
204         pChildWindow = m_pTopWindow;
205 
206     while( pChildWindow->ImplGetClientWindow() )
207         pChildWindow = pChildWindow->ImplGetClientWindow();
208 
209     if( pChildWindow->ImplIsAntiparallel() )
210         pChildWindow->ImplReMirror( location );
211 
212 	aSolarGuard.clear();
213 
214 	if( pChildWindow != m_pCurrentWindow )
215 	{
216 		// fire dragExit on listeners of previous window
217 		fireDragExitEvent( m_pCurrentWindow );
218 
219 		// remember new window
220 		m_pCurrentWindow = pChildWindow;
221 
222 		// fire dragEnter on listeners of current window
223 		nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
224 			dtde.SourceActions, m_aDataFlavorList );
225 	}
226 	else
227 	{
228 		// fire dragOver on listeners of current window
229 		nListeners = fireDragOverEvent( pChildWindow, dtde.Context,	dtde.DropAction, location,
230 			dtde.SourceActions );
231 	}
232 
233 	// reject drag if no listener found
234 	if( nListeners == 0 )
235 	{
236 		OSL_TRACE( "rejecting drag over due to missing listeners." );
237 		dtde.Context->rejectDrag();
238 	}
239 }
240 
241 //==================================================================================================
242 // DNDEventDispatcher::dropActionChanged
243 //==================================================================================================
244 
245 void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde )
246 	throw(RuntimeException)
247 {
248 	MutexGuard aImplGuard( m_aMutex );
249 
250 	Point location( dtde.LocationX, dtde.LocationY );
251 	sal_Int32 nListeners;
252 
253 	// find the window that is toplevel for this coordinates
254 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
255 
256     // because those coordinates come from outside, they must be mirrored if RTL layout is active
257     if( Application::GetSettings().GetLayoutRTL() )
258         m_pTopWindow->ImplMirrorFramePos( location );
259 	Window * pChildWindow = m_pTopWindow->ImplFindWindow( location );
260 
261 	if( NULL == pChildWindow )
262         pChildWindow = m_pTopWindow;
263 
264     while( pChildWindow->ImplGetClientWindow() )
265         pChildWindow = pChildWindow->ImplGetClientWindow();
266 
267     if( pChildWindow->ImplIsAntiparallel() )
268         pChildWindow->ImplReMirror( location );
269 
270 	aSolarGuard.clear();
271 
272 	if( pChildWindow != m_pCurrentWindow )
273 	{
274 		// fire dragExit on listeners of previous window
275 		fireDragExitEvent( m_pCurrentWindow );
276 
277 		// remember new window
278 		m_pCurrentWindow = pChildWindow;
279 
280 		// fire dragEnter on listeners of current window
281 		nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
282 			dtde.SourceActions, m_aDataFlavorList );
283 	}
284 	else
285 	{
286 		// fire dropActionChanged on listeners of current window
287 		nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location,
288 			dtde.SourceActions );
289 	}
290 
291 	// reject drag if no listener found
292 	if( nListeners == 0 )
293 	{
294 		OSL_TRACE( "rejecting dropActionChanged due to missing listeners." );
295 		dtde.Context->rejectDrag();
296 	}
297 }
298 
299 
300 //==================================================================================================
301 // DNDEventDispatcher::dragGestureRecognized
302 //==================================================================================================
303 
304 void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge )
305     throw(RuntimeException)
306 {	MutexGuard aImplGuard( m_aMutex );
307 
308 	Point origin( dge.DragOriginX, dge.DragOriginY );
309 
310 	// find the window that is toplevel for this coordinates
311 	OClearableGuard aSolarGuard( Application::GetSolarMutex() );
312 
313     // because those coordinates come from outside, they must be mirrored if RTL layout is active
314     if( Application::GetSettings().GetLayoutRTL() )
315         m_pTopWindow->ImplMirrorFramePos( origin );
316     Window * pChildWindow = m_pTopWindow->ImplFindWindow( origin );
317 
318 	if( NULL == pChildWindow )
319         pChildWindow = m_pTopWindow;
320 
321     while( pChildWindow->ImplGetClientWindow() )
322         pChildWindow = pChildWindow->ImplGetClientWindow();
323 
324     if( pChildWindow->ImplIsAntiparallel() )
325         pChildWindow->ImplReMirror( origin );
326 
327 	aSolarGuard.clear();
328 
329     fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction );
330 }
331 
332 //==================================================================================================
333 // DNDEventDispatcher::disposing
334 //==================================================================================================
335 
336 void SAL_CALL DNDEventDispatcher::disposing( const EventObject& )
337 	throw(RuntimeException)
338 {
339 }
340 
341 //==================================================================================================
342 // DNDEventDispatcher::acceptDrag
343 //==================================================================================================
344 
345 void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ ) throw(RuntimeException)
346 {
347 }
348 
349 //==================================================================================================
350 // DNDEventDispatcher::rejectDrag
351 //==================================================================================================
352 
353 void SAL_CALL DNDEventDispatcher::rejectDrag() throw(RuntimeException)
354 {
355 }
356 
357 //==================================================================================================
358 // DNDEventDispatcher::fireDragEnterEvent
359 //==================================================================================================
360 
361 sal_Int32 DNDEventDispatcher::fireDragEnterEvent( Window *pWindow,
362 	const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
363 	const Point& rLocation, const sal_Int8 nSourceActions, const Sequence< DataFlavor >& aFlavorList
364 )
365 	throw(RuntimeException)
366 {
367 	sal_Int32 n = 0;
368 
369 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
370 	{
371 		OClearableGuard aGuard( Application::GetSolarMutex() );
372 
373         // set an UI lock
374         pWindow->IncrementLockCount();
375 
376 		// query DropTarget from window
377 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
378 
379 		if( xDropTarget.is() )
380 		{
381 			// retrieve relative mouse position
382 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
383 			aGuard.clear();
384 
385 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent(
386 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList );
387 		}
388 	}
389 
390 	return n;
391 }
392 
393 //==================================================================================================
394 // DNDEventDispatcher::fireDragOverEvent
395 //==================================================================================================
396 
397 sal_Int32 DNDEventDispatcher::fireDragOverEvent( Window *pWindow,
398 	const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
399 	const Point& rLocation, const sal_Int8 nSourceActions
400 )
401 	throw(RuntimeException)
402 {
403 	sal_Int32 n = 0;
404 
405 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
406 	{
407 		OClearableGuard aGuard( Application::GetSolarMutex() );
408 
409 		// query DropTarget from window
410 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
411 
412 		if( xDropTarget.is() )
413 		{
414 			// retrieve relative mouse position
415 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
416 			aGuard.clear();
417 
418 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent(
419 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
420 		}
421 	}
422 
423 	return n;
424 }
425 
426 //==================================================================================================
427 // DNDEventDispatcher::fireDragExitEvent
428 //==================================================================================================
429 
430 sal_Int32 DNDEventDispatcher::fireDragExitEvent( Window *pWindow ) throw(RuntimeException)
431 {
432 	sal_Int32 n = 0;
433 
434 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
435 	{
436 		OClearableGuard aGuard( Application::GetSolarMutex() );
437 
438 		// query DropTarget from window
439 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
440 
441 		aGuard.clear();
442 
443 		if( xDropTarget.is() )
444 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent();
445 
446         // release UI lock
447         pWindow->DecrementLockCount();
448 	}
449 
450 	return n;
451 }
452 
453 //==================================================================================================
454 // DNDEventDispatcher::fireDropActionChangedEvent
455 //==================================================================================================
456 
457 sal_Int32 DNDEventDispatcher::fireDropActionChangedEvent( Window *pWindow,
458 	const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction,
459 	const Point& rLocation, const sal_Int8 nSourceActions
460 )
461 	throw(RuntimeException)
462 {
463 	sal_Int32 n = 0;
464 
465 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
466 	{
467 		OClearableGuard aGuard( Application::GetSolarMutex() );
468 
469 		// query DropTarget from window
470 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
471 
472 		if( xDropTarget.is() )
473 		{
474 			// retrieve relative mouse position
475 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
476 			aGuard.clear();
477 
478 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent(
479 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions );
480 		}
481 	}
482 
483 	return n;
484 }
485 
486 //==================================================================================================
487 // DNDEventDispatcher::fireDropEvent
488 //==================================================================================================
489 
490 sal_Int32 DNDEventDispatcher::fireDropEvent( Window *pWindow,
491 	const Reference< XDropTargetDropContext >& xContext, const sal_Int8 nDropAction, const Point& rLocation,
492 	const sal_Int8 nSourceActions, const Reference< XTransferable >& xTransferable
493 )
494 	throw(RuntimeException)
495 {
496 	sal_Int32 n = 0;
497 
498 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
499 	{
500 		OClearableGuard aGuard( Application::GetSolarMutex() );
501 
502 		// query DropTarget from window
503 		Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget();
504 
505         // window may be destroyed in drop event handler
506         ImplDelData         aDelData;
507         pWindow->ImplAddDel( &aDelData );
508 
509 		if( xDropTarget.is() )
510 		{
511 			// retrieve relative mouse position
512 			Point relLoc = pWindow->ImplFrameToOutput( rLocation );
513 			aGuard.clear();
514 
515 			n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent(
516 				xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable );
517 		}
518 
519         if ( !aDelData.IsDelete() )
520         {
521             pWindow->ImplRemoveDel( &aDelData );
522             // release UI lock
523             pWindow->DecrementLockCount();
524         }
525 
526 	}
527 
528 	return n;
529 }
530 
531 //==================================================================================================
532 // DNDEventDispatcher::fireDragGestureRecognized
533 //==================================================================================================
534 
535 sal_Int32 DNDEventDispatcher::fireDragGestureEvent( Window *pWindow,
536     const Reference< XDragSource >& xSource, const Any event,
537     const Point& rOrigin, const sal_Int8 nDragAction
538 )
539     throw(::com::sun::star::uno::RuntimeException)
540 {
541 	sal_Int32 n = 0;
542 
543 	if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() )
544 	{
545 		OClearableGuard aGuard( Application::GetSolarMutex() );
546 
547 		// query DropTarget from window
548 		Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer();
549 
550 		if( xDragGestureRecognizer.is() )
551 		{
552 			// retrieve relative mouse position
553 			Point relLoc = pWindow->ImplFrameToOutput( rOrigin );
554 			aGuard.clear();
555 
556 			n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent(
557 				nDragAction, relLoc.X(), relLoc.Y(), xSource, event );
558 		}
559 
560         // release UI lock
561         pWindow->DecrementLockCount();
562 	}
563 
564 	return n;
565 }
566