xref: /aoo41x/main/dtrans/source/win32/dnd/target.cxx (revision 48123e16)
1*48123e16SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*48123e16SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*48123e16SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*48123e16SAndrew Rist  * distributed with this work for additional information
6*48123e16SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*48123e16SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*48123e16SAndrew Rist  * "License"); you may not use this file except in compliance
9*48123e16SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*48123e16SAndrew Rist  *
11*48123e16SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*48123e16SAndrew Rist  *
13*48123e16SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*48123e16SAndrew Rist  * software distributed under the License is distributed on an
15*48123e16SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*48123e16SAndrew Rist  * KIND, either express or implied.  See the License for the
17*48123e16SAndrew Rist  * specific language governing permissions and limitations
18*48123e16SAndrew Rist  * under the License.
19*48123e16SAndrew Rist  *
20*48123e16SAndrew Rist  *************************************************************/
21*48123e16SAndrew Rist 
22*48123e16SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_dtrans.hxx"
26cdf0e10cSrcweir #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
27cdf0e10cSrcweir #include <com/sun/star/datatransfer/XTransferable.hpp>
28cdf0e10cSrcweir #include <rtl/unload.h>
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #include <stdio.h>
31cdf0e10cSrcweir #include "target.hxx"
32cdf0e10cSrcweir #include "idroptarget.hxx"
33cdf0e10cSrcweir #include "globals.hxx"
34cdf0e10cSrcweir #include "targetdropcontext.hxx"
35cdf0e10cSrcweir #include "targetdragcontext.hxx"
36cdf0e10cSrcweir #include <rtl/ustring.h>
37cdf0e10cSrcweir using namespace rtl;
38cdf0e10cSrcweir using namespace cppu;
39cdf0e10cSrcweir using namespace osl;
40cdf0e10cSrcweir using namespace com::sun::star::datatransfer;
41cdf0e10cSrcweir using namespace com::sun::star::datatransfer::dnd;
42cdf0e10cSrcweir using namespace com::sun::star::datatransfer::dnd::DNDConstants;
43cdf0e10cSrcweir 
44cdf0e10cSrcweir #define WM_REGISTERDRAGDROP WM_USER + 1
45cdf0e10cSrcweir #define WM_REVOKEDRAGDROP WM_USER + 2
46cdf0e10cSrcweir //--> TRA
47cdf0e10cSrcweir extern Reference< XTransferable > g_XTransferable;
48cdf0e10cSrcweir 
49cdf0e10cSrcweir //<-- TRA
50cdf0e10cSrcweir 
51cdf0e10cSrcweir extern rtl_StandardModuleCount g_moduleCount;
52cdf0e10cSrcweir DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams);
53cdf0e10cSrcweir 
DropTarget(const Reference<XMultiServiceFactory> & sf)54cdf0e10cSrcweir DropTarget::DropTarget( const Reference<XMultiServiceFactory>& sf):
55cdf0e10cSrcweir 	m_hWnd( NULL),
56cdf0e10cSrcweir 	m_serviceFactory( sf),
57cdf0e10cSrcweir 	WeakComponentImplHelper3<XInitialization,XDropTarget, XServiceInfo>(m_mutex),
58cdf0e10cSrcweir 	m_bActive(sal_True),
59cdf0e10cSrcweir 	m_nDefaultActions(ACTION_COPY|ACTION_MOVE|ACTION_LINK|ACTION_DEFAULT),
60cdf0e10cSrcweir 	m_nCurrentDropAction( ACTION_NONE),
61cdf0e10cSrcweir 	m_oleThreadId( 0),
62cdf0e10cSrcweir 	m_pDropTarget( NULL),
63cdf0e10cSrcweir 	m_threadIdWindow(0),
64cdf0e10cSrcweir 	m_threadIdTarget(0),
65cdf0e10cSrcweir 	m_hOleThread(0),
66cdf0e10cSrcweir 	m_nLastDropAction(0)
67cdf0e10cSrcweir 
68cdf0e10cSrcweir 
69cdf0e10cSrcweir {
70cdf0e10cSrcweir 	g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
71cdf0e10cSrcweir }
72cdf0e10cSrcweir 
73cdf0e10cSrcweir 
~DropTarget()74cdf0e10cSrcweir DropTarget::~DropTarget()
75cdf0e10cSrcweir {
76cdf0e10cSrcweir 	g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
77cdf0e10cSrcweir 
78cdf0e10cSrcweir }
79cdf0e10cSrcweir // called from WeakComponentImplHelperX::dispose
80cdf0e10cSrcweir // WeakComponentImplHelper calls disposing before it destroys
81cdf0e10cSrcweir // itself.
82cdf0e10cSrcweir // NOTE: RevokeDragDrop decrements the ref count on the IDropTarget
83cdf0e10cSrcweir // interface. (m_pDropTarget)
84cdf0e10cSrcweir // If the HWND is invalid then it doesn't decrement and
85cdf0e10cSrcweir // the IDropTarget object will live on. MEMORY LEAK
disposing()86cdf0e10cSrcweir void SAL_CALL DropTarget::disposing()
87cdf0e10cSrcweir {
88cdf0e10cSrcweir 	HRESULT hr= S_OK;
89cdf0e10cSrcweir 	if( m_threadIdTarget)
90cdf0e10cSrcweir 	{
91cdf0e10cSrcweir         // Call RevokeDragDrop and wait for the OLE thread to die;
92cdf0e10cSrcweir 		PostThreadMessage( m_threadIdTarget, WM_REVOKEDRAGDROP, (WPARAM)this, 0);
93cdf0e10cSrcweir 		WaitForSingleObject( m_hOleThread, INFINITE);
94cdf0e10cSrcweir 		CloseHandle( m_hOleThread);
95cdf0e10cSrcweir 		//OSL_ENSURE( SUCCEEDED( hr), "HWND not valid!" );
96cdf0e10cSrcweir 	}
97cdf0e10cSrcweir 	else
98cdf0e10cSrcweir 	{
99cdf0e10cSrcweir 		hr= RevokeDragDrop( m_hWnd);
100cdf0e10cSrcweir 		m_hWnd= 0;
101cdf0e10cSrcweir 	}
102cdf0e10cSrcweir 	if( m_pDropTarget)
103cdf0e10cSrcweir     {
104cdf0e10cSrcweir         CoLockObjectExternal( m_pDropTarget, FALSE, TRUE);
105cdf0e10cSrcweir         m_pDropTarget->Release();
106cdf0e10cSrcweir     }
107cdf0e10cSrcweir 
108cdf0e10cSrcweir 	if( m_oleThreadId)
109cdf0e10cSrcweir     {
110cdf0e10cSrcweir         if( m_oleThreadId == CoGetCurrentProcess() )
111cdf0e10cSrcweir             OleUninitialize();
112cdf0e10cSrcweir     }
113cdf0e10cSrcweir 
114cdf0e10cSrcweir }
115cdf0e10cSrcweir 
initialize(const Sequence<Any> & aArguments)116cdf0e10cSrcweir void SAL_CALL DropTarget::initialize( const Sequence< Any >& aArguments )
117cdf0e10cSrcweir 		throw(Exception, RuntimeException)
118cdf0e10cSrcweir {
119cdf0e10cSrcweir     // The window must be registered for Dnd by RegisterDragDrop. We must ensure
120cdf0e10cSrcweir 	// that RegisterDragDrop is called from an STA ( OleInitialize) thread.
121cdf0e10cSrcweir 	// As long as the window is registered we need to receive OLE messages in
122cdf0e10cSrcweir 	// an OLE thread. That is to say, if DropTarget::initialize was called from an
123cdf0e10cSrcweir 	// MTA thread then we create an OLE thread in which the window is registered.
124cdf0e10cSrcweir     // The thread will stay alive until aver RevokeDragDrop has been called.
125cdf0e10cSrcweir 
126cdf0e10cSrcweir 	// Additionally even if RegisterDragDrop is called from an STA thread we have
127cdf0e10cSrcweir 	// to ensure that it is called from the same thread that created the Window
128cdf0e10cSrcweir 	// otherwise meesages sent during DND won't reach the windows message queue.
129cdf0e10cSrcweir 	// Calling AttachThreadInput first would resolve this problem but would block
130cdf0e10cSrcweir 	// the message queue of the calling thread. So if the current thread
131cdf0e10cSrcweir 	// (even if it's an STA thread) and the thread that created the window are not
132cdf0e10cSrcweir 	// identical we need to create a new thread as we do when the calling thread is
133cdf0e10cSrcweir 	// an MTA thread.
134cdf0e10cSrcweir 
135cdf0e10cSrcweir 	if( aArguments.getLength() > 0)
136cdf0e10cSrcweir 	{
137cdf0e10cSrcweir 		// Get the window handle from aArgument. It is needed for RegisterDragDrop.
138cdf0e10cSrcweir 		m_hWnd= *(HWND*)aArguments[0].getValue();
139cdf0e10cSrcweir 		OSL_ASSERT( IsWindow( m_hWnd) );
140cdf0e10cSrcweir 
141cdf0e10cSrcweir 		// Obtain the id of the thread that created the window
142cdf0e10cSrcweir 		m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, NULL);
143cdf0e10cSrcweir 
144cdf0e10cSrcweir 		HRESULT hr= OleInitialize( NULL);
145cdf0e10cSrcweir 
146cdf0e10cSrcweir 		// Current thread is MTA or Current thread and Window thread are not identical
147cdf0e10cSrcweir 		if( hr == RPC_E_CHANGED_MODE || GetCurrentThreadId() != m_threadIdWindow  )
148cdf0e10cSrcweir 		{
149cdf0e10cSrcweir 			OSL_ENSURE( ! m_threadIdTarget,"initialize was called twice");
150cdf0e10cSrcweir 			// create the IDropTargetImplementation
151cdf0e10cSrcweir 			m_pDropTarget= new IDropTargetImpl( *static_cast<DropTarget*>( this) );
152cdf0e10cSrcweir 			m_pDropTarget->AddRef();
153cdf0e10cSrcweir 
154cdf0e10cSrcweir 
155cdf0e10cSrcweir 			// Obtain the id of the thread that created the window
156cdf0e10cSrcweir 			m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, NULL);
157cdf0e10cSrcweir 			// The event is set by the thread that we will create momentarily.
158cdf0e10cSrcweir 			// It indicates that the thread is ready to receive messages.
159cdf0e10cSrcweir 			HANDLE m_evtThreadReady= CreateEvent( NULL, FALSE, FALSE, NULL);
160cdf0e10cSrcweir 
161cdf0e10cSrcweir 			m_hOleThread= CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)DndTargetOleSTAFunc,
162cdf0e10cSrcweir 											&m_evtThreadReady, 0, &m_threadIdTarget);
163cdf0e10cSrcweir 			WaitForSingleObject( m_evtThreadReady, INFINITE);
164cdf0e10cSrcweir 			CloseHandle( m_evtThreadReady);
165cdf0e10cSrcweir 			PostThreadMessage( m_threadIdTarget, WM_REGISTERDRAGDROP, (WPARAM)static_cast<DropTarget*>(this), 0);
166cdf0e10cSrcweir 		}
167cdf0e10cSrcweir 		else if( hr == S_OK || hr == S_FALSE)
168cdf0e10cSrcweir 		{
169cdf0e10cSrcweir 			// current thread is STA
170cdf0e10cSrcweir 			// If OleInitialize has been called by the caller then we must not call
171cdf0e10cSrcweir 			// OleUninitialize
172cdf0e10cSrcweir 			if( hr == S_OK)
173cdf0e10cSrcweir 			{
174cdf0e10cSrcweir 				// caller did not call OleInitialize, so we call OleUninitialize
175cdf0e10cSrcweir 				// remember the thread that will call OleUninitialize
176cdf0e10cSrcweir 				m_oleThreadId= CoGetCurrentProcess(); // get a unique thread id
177cdf0e10cSrcweir 			}
178cdf0e10cSrcweir 
179cdf0e10cSrcweir 			// Get the window handle from aArgument. It is needed for RegisterDragDrop.
180cdf0e10cSrcweir 			// create the IDropTargetImplementation
181cdf0e10cSrcweir 			m_pDropTarget= new IDropTargetImpl( *static_cast<DropTarget*>( this) );
182cdf0e10cSrcweir 			m_pDropTarget->AddRef();
183cdf0e10cSrcweir 			// CoLockObjectExternal is prescribed by the protocol. It bumps up the ref count
184cdf0e10cSrcweir 			if( SUCCEEDED( CoLockObjectExternal( m_pDropTarget, TRUE, FALSE)))
185cdf0e10cSrcweir 			{
186cdf0e10cSrcweir 				if( FAILED( RegisterDragDrop( m_hWnd,  m_pDropTarget) ) )
187cdf0e10cSrcweir 				{
188cdf0e10cSrcweir 					// do clean up if drag and drop is not possible
189cdf0e10cSrcweir 					CoLockObjectExternal( m_pDropTarget, FALSE, FALSE);
190cdf0e10cSrcweir 					m_pDropTarget->Release();
191cdf0e10cSrcweir 					m_hWnd= NULL;
192cdf0e10cSrcweir 				}
193cdf0e10cSrcweir 			}
194cdf0e10cSrcweir 		}
195cdf0e10cSrcweir 		else
196cdf0e10cSrcweir 			throw Exception();
197cdf0e10cSrcweir 
198cdf0e10cSrcweir 	}
199cdf0e10cSrcweir }
200cdf0e10cSrcweir 
201cdf0e10cSrcweir // This function is called as extra thread from DragSource::startDrag.
202cdf0e10cSrcweir // The function carries out a drag and drop operation by calling
203cdf0e10cSrcweir // DoDragDrop. The thread also notifies all XSourceListener.
DndTargetOleSTAFunc(LPVOID pParams)204cdf0e10cSrcweir DWORD WINAPI DndTargetOleSTAFunc(LPVOID pParams)
205cdf0e10cSrcweir {
206cdf0e10cSrcweir 	HRESULT hr= OleInitialize( NULL);
207cdf0e10cSrcweir 	if( SUCCEEDED( hr) )
208cdf0e10cSrcweir 	{
209cdf0e10cSrcweir 		MSG msg;
210cdf0e10cSrcweir 		// force the creation of a message queue
211cdf0e10cSrcweir 		PeekMessage( &msg, (HWND)NULL, 0, 0, PM_NOREMOVE);
212cdf0e10cSrcweir 		// Signal the creator ( DropTarget::initialize) that the thread is
213cdf0e10cSrcweir 		// ready to receive messages.
214cdf0e10cSrcweir 		SetEvent( *(HANDLE*) pParams);
215cdf0e10cSrcweir 		// Thread id is needed for attaching this message queue to the one of the
216cdf0e10cSrcweir 		// thread where the window was created.
217cdf0e10cSrcweir 		DWORD threadId= GetCurrentThreadId();
218cdf0e10cSrcweir 		// We force the creation of a thread message queue. This is necessary
219cdf0e10cSrcweir 		// for a later call to AttachThreadInput
220cdf0e10cSrcweir 		while( GetMessage(&msg, (HWND)NULL, 0, 0) )
221cdf0e10cSrcweir 		{
222cdf0e10cSrcweir 			if( msg.message == WM_REGISTERDRAGDROP)
223cdf0e10cSrcweir 			{
224cdf0e10cSrcweir 				DropTarget *pTarget= (DropTarget*)msg.wParam;
225cdf0e10cSrcweir 				// This thread is attached to the thread that created the window. Hence
226cdf0e10cSrcweir 				// this thread also receives all mouse and keyboard messages which are
227cdf0e10cSrcweir 				// needed
228cdf0e10cSrcweir 				AttachThreadInput( threadId , pTarget->m_threadIdWindow, TRUE );
229cdf0e10cSrcweir 
230cdf0e10cSrcweir 				if( SUCCEEDED( CoLockObjectExternal(pTarget-> m_pDropTarget, TRUE, FALSE)))
231cdf0e10cSrcweir 				{
232cdf0e10cSrcweir 					if( FAILED( RegisterDragDrop( pTarget-> m_hWnd, pTarget-> m_pDropTarget) ) )
233cdf0e10cSrcweir 					{
234cdf0e10cSrcweir 						// do clean up if drag and drop is not possible
235cdf0e10cSrcweir 						CoLockObjectExternal( pTarget->m_pDropTarget, FALSE, FALSE);
236cdf0e10cSrcweir 						pTarget->m_pDropTarget->Release();
237cdf0e10cSrcweir 						pTarget->m_hWnd= NULL;
238cdf0e10cSrcweir 					}
239cdf0e10cSrcweir 				}
240cdf0e10cSrcweir 			}
241cdf0e10cSrcweir 			else if( msg.message == WM_REVOKEDRAGDROP)
242cdf0e10cSrcweir 			{
243cdf0e10cSrcweir 				DropTarget *pTarget= (DropTarget*)msg.wParam;
244cdf0e10cSrcweir 				RevokeDragDrop( pTarget-> m_hWnd);
245cdf0e10cSrcweir 				// Detach this thread from the window thread
246cdf0e10cSrcweir 				AttachThreadInput( threadId, pTarget->m_threadIdWindow, FALSE);
247cdf0e10cSrcweir 				pTarget->m_hWnd= 0;
248cdf0e10cSrcweir 				break;
249cdf0e10cSrcweir 			}
250cdf0e10cSrcweir 			TranslateMessage(  &msg);
251cdf0e10cSrcweir 			DispatchMessage( &msg);
252cdf0e10cSrcweir 		}
253cdf0e10cSrcweir 		OleUninitialize();
254cdf0e10cSrcweir 	}
255cdf0e10cSrcweir 	return 0;
256cdf0e10cSrcweir }
257cdf0e10cSrcweir 
258cdf0e10cSrcweir 
259cdf0e10cSrcweir 
260cdf0e10cSrcweir 
261cdf0e10cSrcweir // XServiceInfo
getImplementationName()262cdf0e10cSrcweir OUString SAL_CALL DropTarget::getImplementationName(  ) throw (RuntimeException)
263cdf0e10cSrcweir {
264cdf0e10cSrcweir     return OUString(RTL_CONSTASCII_USTRINGPARAM(DNDTARGET_IMPL_NAME));;
265cdf0e10cSrcweir }
266cdf0e10cSrcweir // XServiceInfo
supportsService(const OUString & ServiceName)267cdf0e10cSrcweir sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException)
268cdf0e10cSrcweir {
269cdf0e10cSrcweir     if( ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM(DNDTARGET_SERVICE_NAME ))))
270cdf0e10cSrcweir         return sal_True;
271cdf0e10cSrcweir     return sal_False;
272cdf0e10cSrcweir }
273cdf0e10cSrcweir 
getSupportedServiceNames()274cdf0e10cSrcweir Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames(  ) throw (RuntimeException)
275cdf0e10cSrcweir {
276cdf0e10cSrcweir     OUString names[1]= {OUString(RTL_CONSTASCII_USTRINGPARAM(DNDTARGET_SERVICE_NAME))};
277cdf0e10cSrcweir     return Sequence<OUString>(names, 1);
278cdf0e10cSrcweir }
279cdf0e10cSrcweir 
280cdf0e10cSrcweir 
281cdf0e10cSrcweir // XDropTarget ----------------------------------------------------------------
addDropTargetListener(const Reference<XDropTargetListener> & dtl)282cdf0e10cSrcweir void SAL_CALL DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& dtl )
283cdf0e10cSrcweir 		throw(RuntimeException)
284cdf0e10cSrcweir {
285cdf0e10cSrcweir 	rBHelper.addListener( ::getCppuType( &dtl ), dtl );
286cdf0e10cSrcweir }
287cdf0e10cSrcweir 
removeDropTargetListener(const Reference<XDropTargetListener> & dtl)288cdf0e10cSrcweir void SAL_CALL DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& dtl )
289cdf0e10cSrcweir 		throw(RuntimeException)
290cdf0e10cSrcweir {
291cdf0e10cSrcweir 	rBHelper.removeListener( ::getCppuType( &dtl ), dtl );
292cdf0e10cSrcweir }
293cdf0e10cSrcweir 
isActive()294cdf0e10cSrcweir sal_Bool SAL_CALL DropTarget::isActive(  ) throw(RuntimeException)
295cdf0e10cSrcweir {
296cdf0e10cSrcweir 	return m_bActive; //m_bDropTargetRegistered;
297cdf0e10cSrcweir }
298cdf0e10cSrcweir 
299cdf0e10cSrcweir 
setActive(sal_Bool _b)300cdf0e10cSrcweir void SAL_CALL DropTarget::setActive( sal_Bool _b ) throw(RuntimeException)
301cdf0e10cSrcweir {
302cdf0e10cSrcweir 	MutexGuard g(m_mutex);
303cdf0e10cSrcweir     m_bActive= _b;
304cdf0e10cSrcweir }
305cdf0e10cSrcweir 
306cdf0e10cSrcweir 
getDefaultActions()307cdf0e10cSrcweir sal_Int8 SAL_CALL DropTarget::getDefaultActions(  ) throw(RuntimeException)
308cdf0e10cSrcweir {
309cdf0e10cSrcweir 	return m_nDefaultActions;
310cdf0e10cSrcweir }
311cdf0e10cSrcweir 
setDefaultActions(sal_Int8 actions)312cdf0e10cSrcweir void SAL_CALL DropTarget::setDefaultActions( sal_Int8 actions ) throw(RuntimeException)
313cdf0e10cSrcweir {
314cdf0e10cSrcweir 	OSL_ENSURE( actions < 8, "No valid default actions");
315cdf0e10cSrcweir 	m_nDefaultActions= actions;
316cdf0e10cSrcweir }
317cdf0e10cSrcweir 
318cdf0e10cSrcweir 
DragEnter(IDataObject * pDataObj,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)319cdf0e10cSrcweir HRESULT DropTarget::DragEnter( IDataObject *pDataObj,
320cdf0e10cSrcweir 									DWORD grfKeyState,
321cdf0e10cSrcweir 									POINTL pt,
322cdf0e10cSrcweir 									DWORD  *pdwEffect)
323cdf0e10cSrcweir {
324cdf0e10cSrcweir #if defined DBG_CONSOLE_OUT
325cdf0e10cSrcweir 	printf("\nDropTarget::DragEnter state: %x effect %d", grfKeyState, *pdwEffect);
326cdf0e10cSrcweir #endif
327cdf0e10cSrcweir     if( m_bActive )
328cdf0e10cSrcweir     {
329cdf0e10cSrcweir 	    // Intersection of pdwEffect and the allowed actions ( setDefaultActions)
330cdf0e10cSrcweir 	    m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
331cdf0e10cSrcweir 		// m_nLastDropAction has to be set by a listener. If no listener calls
332cdf0e10cSrcweir 		//XDropTargetDragContext::acceptDrag and specifies an action then pdwEffect
333cdf0e10cSrcweir 		// will be DROPEFFECT_NONE throughout
334cdf0e10cSrcweir 		m_nLastDropAction= ACTION_DEFAULT | ACTION_MOVE;
335cdf0e10cSrcweir 
336cdf0e10cSrcweir 	    m_currentDragContext= static_cast<XDropTargetDragContext*>( new TargetDragContext(
337cdf0e10cSrcweir 		    static_cast<DropTarget*>(this) ) );
338cdf0e10cSrcweir 
339cdf0e10cSrcweir 		//--> TRA
340cdf0e10cSrcweir 
341cdf0e10cSrcweir 		// shortcut
342cdf0e10cSrcweir 		if ( g_XTransferable.is( ) )
343cdf0e10cSrcweir 			m_currentData = g_XTransferable;
344cdf0e10cSrcweir 		else
345cdf0e10cSrcweir 		{
346cdf0e10cSrcweir 			// Convert the IDataObject to a XTransferable
347cdf0e10cSrcweir 			m_currentData= m_aDataConverter.createTransferableFromDataObj(
348cdf0e10cSrcweir 				                            m_serviceFactory, IDataObjectPtr(pDataObj));
349cdf0e10cSrcweir 		}
350cdf0e10cSrcweir 
351cdf0e10cSrcweir 		//<-- TRA
352cdf0e10cSrcweir 
353cdf0e10cSrcweir 	    if( m_nCurrentDropAction != ACTION_NONE)
354cdf0e10cSrcweir 	    {
355cdf0e10cSrcweir 		    DropTargetDragEnterEvent e;
356cdf0e10cSrcweir 		    e.SupportedDataFlavors= m_currentData->getTransferDataFlavors();
357cdf0e10cSrcweir 		    e.DropAction= m_nCurrentDropAction;
358cdf0e10cSrcweir 		    e.Source= Reference<XInterface>( static_cast<XDropTarget*>(this),UNO_QUERY);
359cdf0e10cSrcweir 		    e.Context= m_currentDragContext;
360cdf0e10cSrcweir 		    POINT point={ pt.x, pt.y};
361cdf0e10cSrcweir 		    ScreenToClient( m_hWnd, &point);
362cdf0e10cSrcweir 		    e.LocationX= point.x;
363cdf0e10cSrcweir 		    e.LocationY= point.y;
364cdf0e10cSrcweir 		    e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
365cdf0e10cSrcweir 
366cdf0e10cSrcweir 		    fire_dragEnter( e);
367cdf0e10cSrcweir 		    // Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set
368cdf0e10cSrcweir 		    // by the listener (m_nCurrentDropAction) is allowed by the source. Only a allowed action is set
369cdf0e10cSrcweir 		    // in pdwEffect. The listener notification is asynchron, that is we cannot expext that the listener
370cdf0e10cSrcweir 			// has already reacted to the notification.
371cdf0e10cSrcweir 		    // If there is more then one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed
372cdf0e10cSrcweir 		    // then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed.
373cdf0e10cSrcweir 		    // On drop the target should present the user a dialog from which the user may change the action.
374cdf0e10cSrcweir 		    sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
375cdf0e10cSrcweir 			*pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions);
376cdf0e10cSrcweir 	    }
377cdf0e10cSrcweir 	    else
378cdf0e10cSrcweir 	    {
379cdf0e10cSrcweir 		    *pdwEffect= DROPEFFECT_NONE;
380cdf0e10cSrcweir 	    }
381cdf0e10cSrcweir     }
382cdf0e10cSrcweir 	return S_OK;
383cdf0e10cSrcweir }
384cdf0e10cSrcweir 
DragOver(DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)385cdf0e10cSrcweir HRESULT DropTarget::DragOver( DWORD grfKeyState,
386cdf0e10cSrcweir 								   POINTL pt,
387cdf0e10cSrcweir 								   DWORD  *pdwEffect)
388cdf0e10cSrcweir {
389cdf0e10cSrcweir     if( m_bActive)
390cdf0e10cSrcweir     {
391cdf0e10cSrcweir 	    m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
392cdf0e10cSrcweir 
393cdf0e10cSrcweir 	    if( m_nCurrentDropAction)
394cdf0e10cSrcweir 	    {
395cdf0e10cSrcweir 		    DropTargetDragEvent e;
396cdf0e10cSrcweir 		    e.DropAction= m_nCurrentDropAction;
397cdf0e10cSrcweir 		    e.Source= Reference<XInterface>(static_cast<XDropTarget*>(this),UNO_QUERY);
398cdf0e10cSrcweir 		    e.Context= m_currentDragContext;
399cdf0e10cSrcweir 		    POINT point={ pt.x, pt.y};
400cdf0e10cSrcweir 		    ScreenToClient( m_hWnd, &point);
401cdf0e10cSrcweir 		    e.LocationX= point.x;
402cdf0e10cSrcweir 		    e.LocationY= point.y;
403cdf0e10cSrcweir 		    e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
404cdf0e10cSrcweir 
405cdf0e10cSrcweir 		    // if grfKeyState has changed since the last DragOver then fire events.
406cdf0e10cSrcweir 		    // A listener might change m_nCurrentDropAction by calling the
407cdf0e10cSrcweir 		    // XDropTargetDragContext::acceptDrag function. But this is not important
408cdf0e10cSrcweir 		    // because in the afterwards fired dragOver event the action reflects
409cdf0e10cSrcweir 		    // grgKeyState again.
410cdf0e10cSrcweir 			if( m_nLastDropAction != m_nCurrentDropAction)
411cdf0e10cSrcweir 				fire_dropActionChanged( e);
412cdf0e10cSrcweir 
413cdf0e10cSrcweir 		    // The Event contains a XDropTargetDragContext implementation.
414cdf0e10cSrcweir 		    fire_dragOver( e);
415cdf0e10cSrcweir 		    // Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set
416cdf0e10cSrcweir 		    // by the listener (m_nCurrentDropAction) is allowed by the source. Only a allowed action is set
417cdf0e10cSrcweir 		    // in pdwEffect. The listener notification is asynchron, that is we cannot expext that the listener
418cdf0e10cSrcweir 			// has already reacted to the notification.
419cdf0e10cSrcweir 		    // If there is more then one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed
420cdf0e10cSrcweir 		    // then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed.
421cdf0e10cSrcweir 		    // On drop the target should present the user a dialog from which the user may change the action.
422cdf0e10cSrcweir 		    sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
423cdf0e10cSrcweir 			// set the last action to the current if listener has not changed the value yet
424cdf0e10cSrcweir 			*pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions);
425cdf0e10cSrcweir 	    }
426cdf0e10cSrcweir 	    else
427cdf0e10cSrcweir 	    {
428cdf0e10cSrcweir 		    *pdwEffect= DROPEFFECT_NONE;
429cdf0e10cSrcweir 	    }
430cdf0e10cSrcweir     }
431cdf0e10cSrcweir #if defined DBG_CONSOLE_OUT
432cdf0e10cSrcweir 	printf("\nDropTarget::DragOver %d", *pdwEffect );
433cdf0e10cSrcweir #endif
434cdf0e10cSrcweir 	return S_OK;
435cdf0e10cSrcweir }
436cdf0e10cSrcweir 
DragLeave(void)437cdf0e10cSrcweir HRESULT DropTarget::DragLeave( void)
438cdf0e10cSrcweir {
439cdf0e10cSrcweir #if defined DBG_CONSOLE_OUT
440cdf0e10cSrcweir 	printf("\nDropTarget::DragLeave");
441cdf0e10cSrcweir #endif
442cdf0e10cSrcweir     if( m_bActive)
443cdf0e10cSrcweir     {
444cdf0e10cSrcweir 
445cdf0e10cSrcweir 	    m_currentData=0;
446cdf0e10cSrcweir 	    m_currentDragContext= 0;
447cdf0e10cSrcweir 	    m_currentDropContext= 0;
448cdf0e10cSrcweir 		m_nLastDropAction= 0;
449cdf0e10cSrcweir 
450cdf0e10cSrcweir 	    if( m_nDefaultActions != ACTION_NONE)
451cdf0e10cSrcweir 	    {
452cdf0e10cSrcweir 		    DropTargetEvent e;
453cdf0e10cSrcweir 		    e.Source=  static_cast<XDropTarget*>(this);
454cdf0e10cSrcweir 
455cdf0e10cSrcweir 		    fire_dragExit( e);
456cdf0e10cSrcweir 	    }
457cdf0e10cSrcweir     }
458cdf0e10cSrcweir 	return S_OK;
459cdf0e10cSrcweir }
460cdf0e10cSrcweir 
Drop(IDataObject *,DWORD grfKeyState,POINTL pt,DWORD * pdwEffect)461cdf0e10cSrcweir HRESULT DropTarget::Drop( IDataObject  * /*pDataObj*/,
462cdf0e10cSrcweir 				   DWORD grfKeyState,
463cdf0e10cSrcweir 				   POINTL pt,
464cdf0e10cSrcweir 				   DWORD *pdwEffect)
465cdf0e10cSrcweir {
466cdf0e10cSrcweir #if defined DBG_CONSOLE_OUT
467cdf0e10cSrcweir 	printf("\nDropTarget::Drop");
468cdf0e10cSrcweir #endif
469cdf0e10cSrcweir     if( m_bActive)
470cdf0e10cSrcweir     {
471cdf0e10cSrcweir 
472cdf0e10cSrcweir 	    m_bDropComplete= sal_False;
473cdf0e10cSrcweir 
474cdf0e10cSrcweir 	    m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
475cdf0e10cSrcweir 	    m_currentDropContext= static_cast<XDropTargetDropContext*>( new TargetDropContext( static_cast<DropTarget*>(this ))  );
476cdf0e10cSrcweir 	    if( m_nCurrentDropAction)
477cdf0e10cSrcweir 	    {
478cdf0e10cSrcweir 		    DropTargetDropEvent e;
479cdf0e10cSrcweir 		    e.DropAction= m_nCurrentDropAction;
480cdf0e10cSrcweir 		    e.Source= Reference<XInterface>( static_cast<XDropTarget*>(this), UNO_QUERY);
481cdf0e10cSrcweir 		    e.Context= m_currentDropContext;
482cdf0e10cSrcweir 		    POINT point={ pt.x, pt.y};
483cdf0e10cSrcweir 		    ScreenToClient( m_hWnd, &point);
484cdf0e10cSrcweir 		    e.LocationX= point.x;
485cdf0e10cSrcweir 		    e.LocationY= point.y;
486cdf0e10cSrcweir 		    e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
487cdf0e10cSrcweir 		    e.Transferable= m_currentData;
488cdf0e10cSrcweir 		    fire_drop( e);
489cdf0e10cSrcweir 
490cdf0e10cSrcweir 		    //if fire_drop returns than a listener might have modified m_nCurrentDropAction
491cdf0e10cSrcweir 		    if( m_bDropComplete == sal_True)
492cdf0e10cSrcweir 		    {
493cdf0e10cSrcweir 			    sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
494cdf0e10cSrcweir 			    *pdwEffect= dndActionsToSingleDropEffect( m_nCurrentDropAction & allowedActions);
495cdf0e10cSrcweir 		    }
496cdf0e10cSrcweir 		    else
497cdf0e10cSrcweir 			    *pdwEffect= DROPEFFECT_NONE;
498cdf0e10cSrcweir 	    }
499cdf0e10cSrcweir 	    else
500cdf0e10cSrcweir 		    *pdwEffect= DROPEFFECT_NONE;
501cdf0e10cSrcweir 
502cdf0e10cSrcweir 	    m_currentData= 0;
503cdf0e10cSrcweir 	    m_currentDragContext= 0;
504cdf0e10cSrcweir 	    m_currentDropContext= 0;
505cdf0e10cSrcweir 		m_nLastDropAction= 0;
506cdf0e10cSrcweir     }
507cdf0e10cSrcweir 	return S_OK;
508cdf0e10cSrcweir }
509cdf0e10cSrcweir 
510cdf0e10cSrcweir 
511cdf0e10cSrcweir 
fire_drop(const DropTargetDropEvent & dte)512cdf0e10cSrcweir void DropTarget::fire_drop( const DropTargetDropEvent& dte)
513cdf0e10cSrcweir {
514cdf0e10cSrcweir 	OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
515cdf0e10cSrcweir 	if( pContainer)
516cdf0e10cSrcweir 	{
517cdf0e10cSrcweir 		OInterfaceIteratorHelper iter( *pContainer);
518cdf0e10cSrcweir 		while( iter.hasMoreElements())
519cdf0e10cSrcweir 		{
520cdf0e10cSrcweir 			Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
521cdf0e10cSrcweir 			listener->drop( dte);
522cdf0e10cSrcweir 		}
523cdf0e10cSrcweir 	}
524cdf0e10cSrcweir }
525cdf0e10cSrcweir 
fire_dragEnter(const DropTargetDragEnterEvent & e)526cdf0e10cSrcweir void DropTarget::fire_dragEnter( const DropTargetDragEnterEvent& e )
527cdf0e10cSrcweir {
528cdf0e10cSrcweir 	OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
529cdf0e10cSrcweir 	if( pContainer)
530cdf0e10cSrcweir 	{
531cdf0e10cSrcweir 		OInterfaceIteratorHelper iter( *pContainer);
532cdf0e10cSrcweir 		while( iter.hasMoreElements())
533cdf0e10cSrcweir 		{
534cdf0e10cSrcweir 			Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
535cdf0e10cSrcweir 			listener->dragEnter( e);
536cdf0e10cSrcweir 		}
537cdf0e10cSrcweir 	}
538cdf0e10cSrcweir }
539cdf0e10cSrcweir 
fire_dragExit(const DropTargetEvent & dte)540cdf0e10cSrcweir void DropTarget::fire_dragExit( const DropTargetEvent& dte )
541cdf0e10cSrcweir {
542cdf0e10cSrcweir 	OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
543cdf0e10cSrcweir 
544cdf0e10cSrcweir 	if( pContainer)
545cdf0e10cSrcweir 	{
546cdf0e10cSrcweir 		OInterfaceIteratorHelper iter( *pContainer);
547cdf0e10cSrcweir 		while( iter.hasMoreElements())
548cdf0e10cSrcweir 		{
549cdf0e10cSrcweir 			Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
550cdf0e10cSrcweir 			listener->dragExit( dte);
551cdf0e10cSrcweir 		}
552cdf0e10cSrcweir 	}
553cdf0e10cSrcweir }
554cdf0e10cSrcweir 
fire_dragOver(const DropTargetDragEvent & dtde)555cdf0e10cSrcweir void DropTarget::fire_dragOver( const DropTargetDragEvent& dtde )
556cdf0e10cSrcweir {
557cdf0e10cSrcweir 	OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
558cdf0e10cSrcweir 	if( pContainer)
559cdf0e10cSrcweir 	{
560cdf0e10cSrcweir 		OInterfaceIteratorHelper iter( *pContainer );
561cdf0e10cSrcweir 		while( iter.hasMoreElements())
562cdf0e10cSrcweir 		{
563cdf0e10cSrcweir 			Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
564cdf0e10cSrcweir 			listener->dragOver( dtde);
565cdf0e10cSrcweir 		}
566cdf0e10cSrcweir 	}
567cdf0e10cSrcweir }
568cdf0e10cSrcweir 
fire_dropActionChanged(const DropTargetDragEvent & dtde)569cdf0e10cSrcweir void DropTarget::fire_dropActionChanged( const DropTargetDragEvent& dtde )
570cdf0e10cSrcweir {
571cdf0e10cSrcweir 	OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (Reference<XDropTargetListener>* )0 ) );
572cdf0e10cSrcweir 	if( pContainer)
573cdf0e10cSrcweir 	{
574cdf0e10cSrcweir 		OInterfaceIteratorHelper iter( *pContainer);
575cdf0e10cSrcweir 		while( iter.hasMoreElements())
576cdf0e10cSrcweir 		{
577cdf0e10cSrcweir 			Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
578cdf0e10cSrcweir 			listener->dropActionChanged( dtde);
579cdf0e10cSrcweir 		}
580cdf0e10cSrcweir 	}
581cdf0e10cSrcweir }
582cdf0e10cSrcweir 
583cdf0e10cSrcweir // Non - interface functions ============================================================
584cdf0e10cSrcweir // DropTarget fires events to XDropTargetListeners. The event object contains an
585cdf0e10cSrcweir // XDropTargetDropContext implementaion. When the listener calls on that interface
586cdf0e10cSrcweir // then the calls are delegated from DropContext (XDropTargetDropContext) to these
587cdf0e10cSrcweir // functions.
588cdf0e10cSrcweir // Only one listener which visible area is affected is allowed to call on
589cdf0e10cSrcweir // XDropTargetDropContext
590cdf0e10cSrcweir // Returning sal_False would cause the XDropTargetDropContext or ..DragContext implementation
591cdf0e10cSrcweir // to throw an InvalidDNDOperationException, meaning that a Drag is not currently performed.
592cdf0e10cSrcweir // return sal_False results in throwing a InvalidDNDOperationException in the caller.
593cdf0e10cSrcweir 
_acceptDrop(sal_Int8 dropOperation,const Reference<XDropTargetDropContext> & context)594cdf0e10cSrcweir void DropTarget::_acceptDrop(sal_Int8 dropOperation, const Reference<XDropTargetDropContext>& context)
595cdf0e10cSrcweir {
596cdf0e10cSrcweir 	if( context == m_currentDropContext)
597cdf0e10cSrcweir 	{
598cdf0e10cSrcweir 		m_nCurrentDropAction= dropOperation;
599cdf0e10cSrcweir 	}
600cdf0e10cSrcweir }
601cdf0e10cSrcweir 
_rejectDrop(const Reference<XDropTargetDropContext> & context)602cdf0e10cSrcweir void DropTarget::_rejectDrop( const Reference<XDropTargetDropContext>& context)
603cdf0e10cSrcweir {
604cdf0e10cSrcweir 	if( context == m_currentDropContext)
605cdf0e10cSrcweir 	{
606cdf0e10cSrcweir 		m_nCurrentDropAction= ACTION_NONE;
607cdf0e10cSrcweir 	}
608cdf0e10cSrcweir }
609cdf0e10cSrcweir 
_dropComplete(sal_Bool success,const Reference<XDropTargetDropContext> & context)610cdf0e10cSrcweir void DropTarget::_dropComplete(sal_Bool success, const Reference<XDropTargetDropContext>& context)
611cdf0e10cSrcweir {
612cdf0e10cSrcweir 	if(context == m_currentDropContext)
613cdf0e10cSrcweir 	{
614cdf0e10cSrcweir 		m_bDropComplete= success;
615cdf0e10cSrcweir 	}
616cdf0e10cSrcweir }
617cdf0e10cSrcweir // --------------------------------------------------------------------------------------
618cdf0e10cSrcweir // DropTarget fires events to XDropTargetListeners. The event object can contains an
619cdf0e10cSrcweir // XDropTargetDragContext implementaion. When the listener calls on that interface
620cdf0e10cSrcweir // then the calls are delegated from DragContext (XDropTargetDragContext) to these
621cdf0e10cSrcweir // functions.
622cdf0e10cSrcweir // Only one listener which visible area is affected is allowed to call on
623cdf0e10cSrcweir // XDropTargetDragContext
_acceptDrag(sal_Int8 dragOperation,const Reference<XDropTargetDragContext> & context)624cdf0e10cSrcweir void DropTarget::_acceptDrag( sal_Int8 dragOperation, const Reference<XDropTargetDragContext>& context)
625cdf0e10cSrcweir {
626cdf0e10cSrcweir 	if( context == m_currentDragContext)
627cdf0e10cSrcweir 	{
628cdf0e10cSrcweir 		m_nLastDropAction= dragOperation;
629cdf0e10cSrcweir 	}
630cdf0e10cSrcweir }
631cdf0e10cSrcweir 
_rejectDrag(const Reference<XDropTargetDragContext> & context)632cdf0e10cSrcweir void DropTarget::_rejectDrag( const Reference<XDropTargetDragContext>& context)
633cdf0e10cSrcweir {
634cdf0e10cSrcweir 	if(context == m_currentDragContext)
635cdf0e10cSrcweir 	{
636cdf0e10cSrcweir 		m_nLastDropAction= ACTION_NONE;
637cdf0e10cSrcweir 	}
638cdf0e10cSrcweir }
639cdf0e10cSrcweir 
640cdf0e10cSrcweir 
641cdf0e10cSrcweir //--------------------------------------------------------------------------------------
642cdf0e10cSrcweir 
643cdf0e10cSrcweir 
644cdf0e10cSrcweir // This function determines the action dependend on the pressed
645cdf0e10cSrcweir // key modifiers ( CTRL, SHIFT, ALT, Right Mouse Button). The result
646cdf0e10cSrcweir // is then checked against the allowed actions which can be set through
647cdf0e10cSrcweir // XDropTarget::setDefaultActions. Only those values which are also
648cdf0e10cSrcweir // default actions are returned. If setDefaultActions has not been called
649cdf0e10cSrcweir // beforehand the the default actions comprise all possible actions.
650cdf0e10cSrcweir // params: grfKeyState - the modifier keys and mouse buttons currently pressed
getFilteredActions(DWORD grfKeyState,DWORD dwEffect)651cdf0e10cSrcweir inline sal_Int8 DropTarget::getFilteredActions( DWORD grfKeyState, DWORD dwEffect)
652cdf0e10cSrcweir {
653cdf0e10cSrcweir 	sal_Int8 actions= dndOleKeysToAction( grfKeyState, dndOleDropEffectsToActions( dwEffect));
654cdf0e10cSrcweir 	return actions &  m_nDefaultActions;
655cdf0e10cSrcweir }
656cdf0e10cSrcweir 
657cdf0e10cSrcweir 
658