646 lines
24 KiB
C++
646 lines
24 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
|
|
#include <com/sun/star/datatransfer/XTransferable.hpp>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <o3tl/any.hxx>
|
|
|
|
#include <stdio.h>
|
|
#include <win/dnd_target.hxx>
|
|
#include "idroptarget.hxx"
|
|
#include "globals.hxx"
|
|
#include "targetdropcontext.hxx"
|
|
#include "targetdragcontext.hxx"
|
|
#include <rtl/ustring.h>
|
|
#include <osl/thread.h>
|
|
#include <sal/log.hxx>
|
|
#include <comphelper/windowserrorstring.hxx>
|
|
|
|
#include "DOTransferable.hxx"
|
|
|
|
using namespace cppu;
|
|
using namespace osl;
|
|
using namespace com::sun::star::datatransfer;
|
|
using namespace com::sun::star::datatransfer::dnd;
|
|
using namespace com::sun::star::datatransfer::dnd::DNDConstants;
|
|
|
|
#define WM_REGISTERDRAGDROP WM_USER + 1
|
|
#define WM_REVOKEDRAGDROP WM_USER + 2
|
|
|
|
unsigned __stdcall DndTargetOleSTAFunc(void* pParams);
|
|
|
|
DropTarget::DropTarget( const Reference<XComponentContext>& rxContext):
|
|
WeakComponentImplHelper<XInitialization,XDropTarget, XServiceInfo>(m_aMutex),
|
|
m_hWnd( nullptr),
|
|
m_threadIdWindow(0),
|
|
m_threadIdTarget(0),
|
|
m_hOleThread(nullptr),
|
|
m_oleThreadId( 0),
|
|
m_pDropTarget( nullptr),
|
|
m_xContext( rxContext ),
|
|
m_bActive(true),
|
|
m_nDefaultActions(ACTION_COPY|ACTION_MOVE|ACTION_LINK|ACTION_DEFAULT),
|
|
m_nCurrentDropAction( ACTION_NONE),
|
|
m_nLastDropAction(0),
|
|
m_bDropComplete(false)
|
|
{
|
|
}
|
|
|
|
DropTarget::~DropTarget()
|
|
{
|
|
}
|
|
// called from WeakComponentImplHelperX::dispose
|
|
// WeakComponentImplHelper calls disposing before it destroys
|
|
// itself.
|
|
// NOTE: RevokeDragDrop decrements the ref count on the IDropTarget
|
|
// interface. (m_pDropTarget)
|
|
// If the HWND is invalid then it doesn't decrement and
|
|
// the IDropTarget object will live on. MEMORY LEAK
|
|
void SAL_CALL DropTarget::disposing()
|
|
{
|
|
if( m_threadIdTarget)
|
|
{
|
|
// Call RevokeDragDrop and wait for the OLE thread to die;
|
|
PostThreadMessageW( m_threadIdTarget, WM_REVOKEDRAGDROP, reinterpret_cast<WPARAM>(this), 0);
|
|
WaitForSingleObject( m_hOleThread, INFINITE);
|
|
CloseHandle( m_hOleThread);
|
|
//OSL_ENSURE( SUCCEEDED( hr), "HWND not valid!" );
|
|
}
|
|
else
|
|
{
|
|
RevokeDragDrop( m_hWnd);
|
|
m_hWnd= nullptr;
|
|
}
|
|
if( m_pDropTarget)
|
|
{
|
|
CoLockObjectExternal( m_pDropTarget, FALSE, TRUE);
|
|
m_pDropTarget->Release();
|
|
m_pDropTarget = nullptr;
|
|
}
|
|
|
|
if( m_oleThreadId)
|
|
{
|
|
if( m_oleThreadId == CoGetCurrentProcess() )
|
|
OleUninitialize();
|
|
}
|
|
|
|
}
|
|
|
|
void SAL_CALL DropTarget::initialize( const Sequence< Any >& aArguments )
|
|
{
|
|
// The window must be registered for Dnd by RegisterDragDrop. We must ensure
|
|
// that RegisterDragDrop is called from an STA ( OleInitialize) thread.
|
|
// As long as the window is registered we need to receive OLE messages in
|
|
// an OLE thread. That is to say, if DropTarget::initialize was called from an
|
|
// MTA thread then we create an OLE thread in which the window is registered.
|
|
// The thread will stay alive until aver RevokeDragDrop has been called.
|
|
|
|
// Additionally even if RegisterDragDrop is called from an STA thread we have
|
|
// to ensure that it is called from the same thread that created the Window
|
|
// otherwise messages sent during DND won't reach the windows message queue.
|
|
// Calling AttachThreadInput first would resolve this problem but would block
|
|
// the message queue of the calling thread. So if the current thread
|
|
// (even if it's an STA thread) and the thread that created the window are not
|
|
// identical we need to create a new thread as we do when the calling thread is
|
|
// an MTA thread.
|
|
|
|
if( aArguments.getLength() > 0)
|
|
{
|
|
// Get the window handle from aArgument. It is needed for RegisterDragDrop.
|
|
m_hWnd= reinterpret_cast<HWND>(static_cast<sal_uIntPtr>(*o3tl::doAccess<sal_uInt64>(aArguments[0])));
|
|
OSL_ASSERT( IsWindow( m_hWnd) );
|
|
|
|
// Obtain the id of the thread that created the window
|
|
m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, nullptr);
|
|
|
|
HRESULT hr= OleInitialize( nullptr);
|
|
|
|
// Current thread is MTA or Current thread and Window thread are not identical
|
|
if( hr == RPC_E_CHANGED_MODE || GetCurrentThreadId() != m_threadIdWindow )
|
|
{
|
|
OSL_ENSURE( ! m_threadIdTarget,"initialize was called twice");
|
|
// create the IDropTargetImplementation
|
|
m_pDropTarget= new IDropTargetImpl( *this );
|
|
m_pDropTarget->AddRef();
|
|
|
|
// Obtain the id of the thread that created the window
|
|
m_threadIdWindow= GetWindowThreadProcessId( m_hWnd, nullptr);
|
|
// The event is set by the thread that we will create momentarily.
|
|
// It indicates that the thread is ready to receive messages.
|
|
HANDLE m_evtThreadReady= CreateEventW( nullptr, FALSE, FALSE, nullptr);
|
|
|
|
m_hOleThread = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, DndTargetOleSTAFunc,
|
|
&m_evtThreadReady, 0, &m_threadIdTarget));
|
|
WaitForSingleObject( m_evtThreadReady, INFINITE);
|
|
CloseHandle( m_evtThreadReady);
|
|
PostThreadMessageW( m_threadIdTarget, WM_REGISTERDRAGDROP, reinterpret_cast<WPARAM>(this), 0);
|
|
}
|
|
else if( hr == S_OK || hr == S_FALSE)
|
|
{
|
|
// current thread is STA
|
|
// If OleInitialize has been called by the caller then we must not call
|
|
// OleUninitialize
|
|
if( hr == S_OK)
|
|
{
|
|
// caller did not call OleInitialize, so we call OleUninitialize
|
|
// remember the thread that will call OleUninitialize
|
|
m_oleThreadId= CoGetCurrentProcess(); // get a unique thread id
|
|
}
|
|
|
|
// Get the window handle from aArgument. It is needed for RegisterDragDrop.
|
|
// create the IDropTargetImplementation
|
|
m_pDropTarget= new IDropTargetImpl( *this );
|
|
m_pDropTarget->AddRef();
|
|
// CoLockObjectExternal is prescribed by the protocol. It bumps up the ref count
|
|
if( SUCCEEDED( CoLockObjectExternal( m_pDropTarget, TRUE, FALSE)))
|
|
{
|
|
if( FAILED( RegisterDragDrop( m_hWnd, m_pDropTarget) ) )
|
|
{
|
|
// do clean up if drag and drop is not possible
|
|
CoLockObjectExternal( m_pDropTarget, FALSE, FALSE);
|
|
m_pDropTarget->Release();
|
|
m_pDropTarget = nullptr;
|
|
m_hWnd= nullptr;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
throw Exception("OleInitialize failed with " + OUString::number(hr), nullptr);
|
|
|
|
}
|
|
}
|
|
|
|
// This function is called as extra thread from DragSource::startDrag.
|
|
// The function carries out a drag and drop operation by calling
|
|
// DoDragDrop. The thread also notifies all XSourceListener.
|
|
unsigned __stdcall DndTargetOleSTAFunc(void* pParams)
|
|
{
|
|
osl_setThreadName("DropTarget DndTargetOleSTAFunc");
|
|
|
|
HRESULT hr= OleInitialize( nullptr);
|
|
if( SUCCEEDED( hr) )
|
|
{
|
|
MSG msg;
|
|
// force the creation of a message queue
|
|
PeekMessageW( &msg, nullptr, 0, 0, PM_NOREMOVE);
|
|
// Signal the creator ( DropTarget::initialize) that the thread is
|
|
// ready to receive messages.
|
|
SetEvent( *static_cast<HANDLE*>(pParams));
|
|
// Thread id is needed for attaching this message queue to the one of the
|
|
// thread where the window was created.
|
|
DWORD threadId= GetCurrentThreadId();
|
|
// We force the creation of a thread message queue. This is necessary
|
|
// for a later call to AttachThreadInput
|
|
for (;;)
|
|
{
|
|
int const bRet = GetMessageW(&msg, nullptr, 0, 0);
|
|
if (bRet == 0)
|
|
{
|
|
break;
|
|
}
|
|
if (-1 == bRet)
|
|
{
|
|
SAL_WARN("vcl.win.dtrans", "GetMessageW failed: " << WindowsErrorString(GetLastError()));
|
|
break;
|
|
}
|
|
if( msg.message == WM_REGISTERDRAGDROP)
|
|
{
|
|
DropTarget *pTarget= reinterpret_cast<DropTarget*>(msg.wParam);
|
|
// This thread is attached to the thread that created the window. Hence
|
|
// this thread also receives all mouse and keyboard messages which are
|
|
// needed
|
|
AttachThreadInput( threadId , pTarget->m_threadIdWindow, TRUE );
|
|
|
|
if( SUCCEEDED( CoLockObjectExternal(pTarget-> m_pDropTarget, TRUE, FALSE)))
|
|
{
|
|
if( FAILED( RegisterDragDrop( pTarget-> m_hWnd, pTarget-> m_pDropTarget) ) )
|
|
{
|
|
// do clean up if drag and drop is not possible
|
|
CoLockObjectExternal( pTarget->m_pDropTarget, FALSE, FALSE);
|
|
pTarget->m_pDropTarget->Release();
|
|
pTarget->m_pDropTarget = nullptr;
|
|
pTarget->m_hWnd= nullptr;
|
|
}
|
|
}
|
|
}
|
|
else if( msg.message == WM_REVOKEDRAGDROP)
|
|
{
|
|
DropTarget *pTarget= reinterpret_cast<DropTarget*>(msg.wParam);
|
|
RevokeDragDrop( pTarget-> m_hWnd);
|
|
// Detach this thread from the window thread
|
|
AttachThreadInput( threadId, pTarget->m_threadIdWindow, FALSE);
|
|
pTarget->m_hWnd= nullptr;
|
|
break;
|
|
}
|
|
TranslateMessage( &msg);
|
|
DispatchMessageW( &msg);
|
|
}
|
|
OleUninitialize();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// XServiceInfo
|
|
OUString SAL_CALL DropTarget::getImplementationName( )
|
|
{
|
|
return "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1";
|
|
}
|
|
// XServiceInfo
|
|
sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName )
|
|
{
|
|
return cppu::supportsService(this, ServiceName);
|
|
}
|
|
|
|
Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( )
|
|
{
|
|
return { "com.sun.star.datatransfer.dnd.OleDropTarget" };
|
|
}
|
|
|
|
// XDropTarget
|
|
void SAL_CALL DropTarget::addDropTargetListener( const Reference< XDropTargetListener >& dtl )
|
|
{
|
|
rBHelper.addListener( cppu::UnoType<decltype(dtl)>::get(), dtl );
|
|
}
|
|
|
|
void SAL_CALL DropTarget::removeDropTargetListener( const Reference< XDropTargetListener >& dtl )
|
|
{
|
|
rBHelper.removeListener( cppu::UnoType<decltype(dtl)>::get(), dtl );
|
|
}
|
|
|
|
sal_Bool SAL_CALL DropTarget::isActive( )
|
|
{
|
|
return m_bActive; //m_bDropTargetRegistered;
|
|
}
|
|
|
|
void SAL_CALL DropTarget::setActive( sal_Bool _b )
|
|
{
|
|
MutexGuard g(m_aMutex);
|
|
m_bActive= _b;
|
|
}
|
|
|
|
sal_Int8 SAL_CALL DropTarget::getDefaultActions( )
|
|
{
|
|
return m_nDefaultActions;
|
|
}
|
|
|
|
void SAL_CALL DropTarget::setDefaultActions( sal_Int8 actions )
|
|
{
|
|
OSL_ENSURE( actions < 8, "No valid default actions");
|
|
m_nDefaultActions= actions;
|
|
}
|
|
|
|
HRESULT DropTarget::DragEnter( IDataObject *pDataObj,
|
|
DWORD grfKeyState,
|
|
POINTL pt,
|
|
DWORD *pdwEffect)
|
|
{
|
|
#if defined DBG_CONSOLE_OUT
|
|
printf("\nDropTarget::DragEnter state: %x effect %d", grfKeyState, *pdwEffect);
|
|
#endif
|
|
if( m_bActive )
|
|
{
|
|
// Intersection of pdwEffect and the allowed actions ( setDefaultActions)
|
|
m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
|
|
// m_nLastDropAction has to be set by a listener. If no listener calls
|
|
//XDropTargetDragContext::acceptDrag and specifies an action then pdwEffect
|
|
// will be DROPEFFECT_NONE throughout
|
|
m_nLastDropAction= ACTION_DEFAULT | ACTION_MOVE;
|
|
|
|
m_currentDragContext = new TargetDragContext(this);
|
|
|
|
//--> TRA
|
|
|
|
// shortcut
|
|
if ( g_XTransferable.is( ) )
|
|
m_currentData = g_XTransferable;
|
|
else
|
|
{
|
|
// Convert the IDataObject to a XTransferable
|
|
m_currentData = new CDOTransferable(m_xContext, IDataObjectPtr(pDataObj));
|
|
}
|
|
|
|
//<-- TRA
|
|
|
|
if( m_nCurrentDropAction != ACTION_NONE)
|
|
{
|
|
DropTargetDragEnterEvent e;
|
|
e.SupportedDataFlavors= m_currentData->getTransferDataFlavors();
|
|
e.DropAction= m_nCurrentDropAction;
|
|
e.Source.set( static_cast<XDropTarget*>(this),UNO_QUERY);
|
|
e.Context= m_currentDragContext;
|
|
POINT point={ pt.x, pt.y};
|
|
ScreenToClient( m_hWnd, &point);
|
|
e.LocationX= point.x;
|
|
e.LocationY= point.y;
|
|
e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
|
|
|
|
fire_dragEnter( e);
|
|
// Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set
|
|
// by the listener (m_nCurrentDropAction) is allowed by the source. Only an allowed action is set
|
|
// in pdwEffect. The listener notification is asynchronous, that is we cannot expect that the listener
|
|
// has already reacted to the notification.
|
|
// If there is more than one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed
|
|
// then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed.
|
|
// On drop the target should present the user a dialog from which the user may change the action.
|
|
sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
|
|
*pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions);
|
|
}
|
|
else
|
|
{
|
|
*pdwEffect= DROPEFFECT_NONE;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DropTarget::DragOver( DWORD grfKeyState,
|
|
POINTL pt,
|
|
DWORD *pdwEffect)
|
|
{
|
|
if( m_bActive)
|
|
{
|
|
m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
|
|
|
|
if( m_nCurrentDropAction)
|
|
{
|
|
DropTargetDragEvent e;
|
|
e.DropAction= m_nCurrentDropAction;
|
|
e.Source.set(static_cast<XDropTarget*>(this),UNO_QUERY);
|
|
e.Context= m_currentDragContext;
|
|
POINT point={ pt.x, pt.y};
|
|
ScreenToClient( m_hWnd, &point);
|
|
e.LocationX= point.x;
|
|
e.LocationY= point.y;
|
|
e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
|
|
|
|
// if grfKeyState has changed since the last DragOver then fire events.
|
|
// A listener might change m_nCurrentDropAction by calling the
|
|
// XDropTargetDragContext::acceptDrag function. But this is not important
|
|
// because in the afterwards fired dragOver event the action reflects
|
|
// grgKeyState again.
|
|
if( m_nLastDropAction != m_nCurrentDropAction)
|
|
fire_dropActionChanged( e);
|
|
|
|
// The Event contains a XDropTargetDragContext implementation.
|
|
fire_dragOver( e);
|
|
// Check if the action derived from grfKeyState (m_nCurrentDropAction) or the action set
|
|
// by the listener (m_nCurrentDropAction) is allowed by the source. Only an allowed action is set
|
|
// in pdwEffect. The listener notification is asynchronous, that is we cannot expect that the listener
|
|
// has already reacted to the notification.
|
|
// If there is more than one valid action which is the case when ALT or RIGHT MOUSE BUTTON is pressed
|
|
// then getDropEffect returns DROPEFFECT_MOVE which is the default value if no other modifier is pressed.
|
|
// On drop the target should present the user a dialog from which the user may change the action.
|
|
sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
|
|
// set the last action to the current if listener has not changed the value yet
|
|
*pdwEffect= dndActionsToSingleDropEffect( m_nLastDropAction & allowedActions);
|
|
}
|
|
else
|
|
{
|
|
*pdwEffect= DROPEFFECT_NONE;
|
|
}
|
|
}
|
|
#if defined DBG_CONSOLE_OUT
|
|
printf("\nDropTarget::DragOver %d", *pdwEffect );
|
|
#endif
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DropTarget::DragLeave()
|
|
{
|
|
#if defined DBG_CONSOLE_OUT
|
|
printf("\nDropTarget::DragLeave");
|
|
#endif
|
|
if( m_bActive)
|
|
{
|
|
|
|
m_currentData=nullptr;
|
|
m_currentDragContext= nullptr;
|
|
m_currentDropContext= nullptr;
|
|
m_nLastDropAction= 0;
|
|
|
|
if( m_nDefaultActions != ACTION_NONE)
|
|
{
|
|
DropTargetEvent e;
|
|
e.Source= static_cast<XDropTarget*>(this);
|
|
|
|
fire_dragExit( e);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT DropTarget::Drop( IDataObject * /*pDataObj*/,
|
|
DWORD grfKeyState,
|
|
POINTL pt,
|
|
DWORD *pdwEffect)
|
|
{
|
|
#if defined DBG_CONSOLE_OUT
|
|
printf("\nDropTarget::Drop");
|
|
#endif
|
|
if( m_bActive)
|
|
{
|
|
|
|
m_bDropComplete= false;
|
|
|
|
m_nCurrentDropAction= getFilteredActions( grfKeyState, *pdwEffect);
|
|
m_currentDropContext = new TargetDropContext(this);
|
|
if( m_nCurrentDropAction)
|
|
{
|
|
DropTargetDropEvent e;
|
|
e.DropAction= m_nCurrentDropAction;
|
|
e.Source.set( static_cast<XDropTarget*>(this), UNO_QUERY);
|
|
e.Context= m_currentDropContext;
|
|
POINT point={ pt.x, pt.y};
|
|
ScreenToClient( m_hWnd, &point);
|
|
e.LocationX= point.x;
|
|
e.LocationY= point.y;
|
|
e.SourceActions= dndOleDropEffectsToActions( *pdwEffect);
|
|
e.Transferable= m_currentData;
|
|
fire_drop( e);
|
|
|
|
//if fire_drop returns than a listener might have modified m_nCurrentDropAction
|
|
if( m_bDropComplete )
|
|
{
|
|
sal_Int8 allowedActions= dndOleDropEffectsToActions( *pdwEffect);
|
|
*pdwEffect= dndActionsToSingleDropEffect( m_nCurrentDropAction & allowedActions);
|
|
}
|
|
else
|
|
*pdwEffect= DROPEFFECT_NONE;
|
|
}
|
|
else
|
|
*pdwEffect= DROPEFFECT_NONE;
|
|
|
|
m_currentData= nullptr;
|
|
m_currentDragContext= nullptr;
|
|
m_currentDropContext= nullptr;
|
|
m_nLastDropAction= 0;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
void DropTarget::fire_drop( const DropTargetDropEvent& dte)
|
|
{
|
|
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
|
|
if( pContainer)
|
|
{
|
|
OInterfaceIteratorHelper iter( *pContainer);
|
|
while( iter.hasMoreElements())
|
|
{
|
|
Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
|
|
listener->drop( dte);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DropTarget::fire_dragEnter( const DropTargetDragEnterEvent& e )
|
|
{
|
|
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
|
|
if( pContainer)
|
|
{
|
|
OInterfaceIteratorHelper iter( *pContainer);
|
|
while( iter.hasMoreElements())
|
|
{
|
|
Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
|
|
listener->dragEnter( e);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DropTarget::fire_dragExit( const DropTargetEvent& dte )
|
|
{
|
|
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
|
|
|
|
if( pContainer)
|
|
{
|
|
OInterfaceIteratorHelper iter( *pContainer);
|
|
while( iter.hasMoreElements())
|
|
{
|
|
Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
|
|
listener->dragExit( dte);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DropTarget::fire_dragOver( const DropTargetDragEvent& dtde )
|
|
{
|
|
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
|
|
if( pContainer)
|
|
{
|
|
OInterfaceIteratorHelper iter( *pContainer );
|
|
while( iter.hasMoreElements())
|
|
{
|
|
Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
|
|
listener->dragOver( dtde);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DropTarget::fire_dropActionChanged( const DropTargetDragEvent& dtde )
|
|
{
|
|
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
|
|
if( pContainer)
|
|
{
|
|
OInterfaceIteratorHelper iter( *pContainer);
|
|
while( iter.hasMoreElements())
|
|
{
|
|
Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
|
|
listener->dropActionChanged( dtde);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Non - interface functions
|
|
// DropTarget fires events to XDropTargetListeners. The event object contains an
|
|
// XDropTargetDropContext implementation. When the listener calls on that interface
|
|
// then the calls are delegated from DropContext (XDropTargetDropContext) to these
|
|
// functions.
|
|
// Only one listener which visible area is affected is allowed to call on
|
|
// XDropTargetDropContext
|
|
// Returning sal_False would cause the XDropTargetDropContext or ..DragContext implementation
|
|
// to throw an InvalidDNDOperationException, meaning that a Drag is not currently performed.
|
|
// return sal_False results in throwing an InvalidDNDOperationException in the caller.
|
|
|
|
void DropTarget::_acceptDrop(sal_Int8 dropOperation, const Reference<XDropTargetDropContext>& context)
|
|
{
|
|
if( context == m_currentDropContext)
|
|
{
|
|
m_nCurrentDropAction= dropOperation;
|
|
}
|
|
}
|
|
|
|
void DropTarget::_rejectDrop( const Reference<XDropTargetDropContext>& context)
|
|
{
|
|
if( context == m_currentDropContext)
|
|
{
|
|
m_nCurrentDropAction= ACTION_NONE;
|
|
}
|
|
}
|
|
|
|
void DropTarget::_dropComplete(bool success, const Reference<XDropTargetDropContext>& context)
|
|
{
|
|
if(context == m_currentDropContext)
|
|
{
|
|
m_bDropComplete= success;
|
|
}
|
|
}
|
|
|
|
// DropTarget fires events to XDropTargetListeners. The event object can contains an
|
|
// XDropTargetDragContext implementation. When the listener calls on that interface
|
|
// then the calls are delegated from DragContext (XDropTargetDragContext) to these
|
|
// functions.
|
|
// Only one listener which visible area is affected is allowed to call on
|
|
// XDropTargetDragContext
|
|
void DropTarget::_acceptDrag( sal_Int8 dragOperation, const Reference<XDropTargetDragContext>& context)
|
|
{
|
|
if( context == m_currentDragContext)
|
|
{
|
|
m_nLastDropAction= dragOperation;
|
|
}
|
|
}
|
|
|
|
void DropTarget::_rejectDrag( const Reference<XDropTargetDragContext>& context)
|
|
{
|
|
if(context == m_currentDragContext)
|
|
{
|
|
m_nLastDropAction= ACTION_NONE;
|
|
}
|
|
}
|
|
|
|
// This function determines the action dependent on the pressed
|
|
// key modifiers ( CTRL, SHIFT, ALT, Right Mouse Button). The result
|
|
// is then checked against the allowed actions which can be set through
|
|
// XDropTarget::setDefaultActions. Only those values which are also
|
|
// default actions are returned. If setDefaultActions has not been called
|
|
// beforehand the default actions comprise all possible actions.
|
|
// params: grfKeyState - the modifier keys and mouse buttons currently pressed
|
|
inline sal_Int8 DropTarget::getFilteredActions( DWORD grfKeyState, DWORD dwEffect)
|
|
{
|
|
sal_Int8 actions= dndOleKeysToAction( grfKeyState, dndOleDropEffectsToActions( dwEffect));
|
|
return actions & m_nDefaultActions;
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
|
|
dtrans_DropTarget_get_implementation(
|
|
css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
|
|
{
|
|
return cppu::acquire(new DropTarget(context));
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|