xref: /trunk/main/vcl/source/window/dndevdis.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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