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 10cdf0e10cSrcweir * 11*48123e16SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 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. 19cdf0e10cSrcweir * 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 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 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 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 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. 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 262cdf0e10cSrcweir OUString SAL_CALL DropTarget::getImplementationName( ) throw (RuntimeException) 263cdf0e10cSrcweir { 264cdf0e10cSrcweir return OUString(RTL_CONSTASCII_USTRINGPARAM(DNDTARGET_IMPL_NAME));; 265cdf0e10cSrcweir } 266cdf0e10cSrcweir // XServiceInfo 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 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 ---------------------------------------------------------------- 282cdf0e10cSrcweir void SAL_CALL DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& dtl ) 283cdf0e10cSrcweir throw(RuntimeException) 284cdf0e10cSrcweir { 285cdf0e10cSrcweir rBHelper.addListener( ::getCppuType( &dtl ), dtl ); 286cdf0e10cSrcweir } 287cdf0e10cSrcweir 288cdf0e10cSrcweir void SAL_CALL DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& dtl ) 289cdf0e10cSrcweir throw(RuntimeException) 290cdf0e10cSrcweir { 291cdf0e10cSrcweir rBHelper.removeListener( ::getCppuType( &dtl ), dtl ); 292cdf0e10cSrcweir } 293cdf0e10cSrcweir 294cdf0e10cSrcweir sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException) 295cdf0e10cSrcweir { 296cdf0e10cSrcweir return m_bActive; //m_bDropTargetRegistered; 297cdf0e10cSrcweir } 298cdf0e10cSrcweir 299cdf0e10cSrcweir 300cdf0e10cSrcweir void SAL_CALL DropTarget::setActive( sal_Bool _b ) throw(RuntimeException) 301cdf0e10cSrcweir { 302cdf0e10cSrcweir MutexGuard g(m_mutex); 303cdf0e10cSrcweir m_bActive= _b; 304cdf0e10cSrcweir } 305cdf0e10cSrcweir 306cdf0e10cSrcweir 307cdf0e10cSrcweir sal_Int8 SAL_CALL DropTarget::getDefaultActions( ) throw(RuntimeException) 308cdf0e10cSrcweir { 309cdf0e10cSrcweir return m_nDefaultActions; 310cdf0e10cSrcweir } 311cdf0e10cSrcweir 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 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 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 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 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 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 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 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 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 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 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 602cdf0e10cSrcweir void DropTarget::_rejectDrop( const Reference<XDropTargetDropContext>& context) 603cdf0e10cSrcweir { 604cdf0e10cSrcweir if( context == m_currentDropContext) 605cdf0e10cSrcweir { 606cdf0e10cSrcweir m_nCurrentDropAction= ACTION_NONE; 607cdf0e10cSrcweir } 608cdf0e10cSrcweir } 609cdf0e10cSrcweir 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 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 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 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