blob: b7e32c114b951845bfff72f4b48f41f187769320 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_dtrans.hxx"
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
#include <com/sun/star/datatransfer/XTransferable.hpp>
#include <rtl/ustring.h>
#include <cppuhelper/implbase1.hxx>
#include <vcl/window.hxx>
#include "globals.hxx"
#include "DropTarget.hxx"
#include "DragSource.hxx"
#include "OTransferable.hxx"
using namespace com::sun::star;
using namespace com::sun::star::io;
using namespace com::sun::star::datatransfer::dnd::DNDConstants;
DropTarget::DropTarget( const Reference<XMultiServiceFactory>& sf):
WeakComponentImplHelper5< XInitialization,
XDropTarget,
XDropTargetDragContext,
XDropTargetDropContext,
XServiceInfo>(m_aMutex),
m_serviceFactory( sf),
dragEnterEmulation( true),
mbActive(false),
mDragSourceSupportedActions(ACTION_NONE),
mSelectedDropAction(ACTION_NONE),
mDefaultActions(ACTION_COPY_OR_MOVE | ACTION_LINK | ACTION_DEFAULT)
{
g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}
DropTarget::~DropTarget()
{
debug_printf("DropTarget::~DropTarget");
// This will free the previous instance if present,
// so it removes the tmp file
mXTransferable = Reference<XTransferable>();
g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}
void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments)
throw(Exception)
{
if (aArguments.getLength() < 2) {
throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")),
static_cast<OWeakObject*>(this));
}
m_hWnd = *(HWND*) aArguments[0].getValue();
debug_printf("DropTarget::initialize hwnd %x", m_hWnd);
// subclass window to allow intercepting D&D messages
defWndProc = WinSubclassWindow( m_hWnd, dndFrameProc);
SetWindowDropTargetPtr( m_hWnd, this);
}
// called from WeakComponentImplHelperX::dispose
// WeakComponentImplHelper calls disposing before it destroys
// itself.
void SAL_CALL DropTarget::disposing()
{
debug_printf("DropTarget::disposing hwnd %x", m_hWnd);
// revert window subclassing
WinSubclassWindow( m_hWnd, defWndProc);
defWndProc = NULL;
SetWindowDropTargetPtr( m_hWnd, 0);
}
void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
throw(RuntimeException)
{
debug_printf("DropTarget::addDropTargetListener hwnd %x", m_hWnd);
rBHelper.addListener(::getCppuType(&dtl), dtl);
}
void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
throw(RuntimeException)
{
debug_printf("DropTarget::removeDropTargetListener hwnd %x", m_hWnd);
rBHelper.removeListener(::getCppuType(&dtl), dtl);
}
sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException)
{
debug_printf("DropTarget::isActive %d", mbActive);
return mbActive;
}
void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
{
debug_printf("DropTarget::setActive %d", active);
mbActive = active;
}
sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
{
debug_printf("DropTarget::getDefaultActions %d", mDefaultActions);
return mDefaultActions;
}
void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException)
{
OSL_ENSURE( actions < 8, "No valid default actions");
mDefaultActions= actions;
}
//
// XDropTargetDragContext
//
// Non - interface functions ============================================================
// DropTarget fires events to XDropTargetListeners. The event object can contains an
// XDropTargetDragContext implementaion. 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 SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException)
{
debug_printf("DropTarget::acceptDrag hwnd %x, dragOperation %d", m_hWnd, dragOperation);
mSelectedDropAction = dragOperation;
}
void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException)
{
debug_printf("DropTarget::rejectDrag hwnd %x", m_hWnd);
mSelectedDropAction = ACTION_NONE;
}
//
// XDropTargetDropContext
//
// Non - interface functions ============================================================
// DropTarget fires events to XDropTargetListeners. The event object contains an
// XDropTargetDropContext implementaion. 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 a InvalidDNDOperationException in the caller.
//
void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException)
{
debug_printf("DropTarget::acceptDrop hwnd %x, dragOperation %d", m_hWnd, dropOperation);
mSelectedDropAction = dropOperation;
}
void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
{
debug_printf("DropTarget::rejectDrop hwnd %x", m_hWnd);
mSelectedDropAction = ACTION_NONE;
}
void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException)
{
debug_printf("DropTarget::dropComplete hwnd %x", m_hWnd);
// reset action flags
mDragSourceSupportedActions = ACTION_NONE;
mSelectedDropAction = ACTION_NONE;
// enable drag enter emulation again
dragEnterEmulation = true;
// free local transferable list on next d&d or destruction
// post a dummy message to source window to allow DragSource
// release resources and close internal d&d
if (DragSource::g_DragSourceHwnd != NULLHANDLE) {
debug_printf("DropTarget::renderComplete post DM_AOO_ENDCONVERSATION to source");
WinPostMsg( DragSource::g_DragSourceHwnd, DM_AOO_ENDCONVERSATION, 0,
MPFROMSHORT(success ? DMFL_TARGETSUCCESSFUL : DMFL_TARGETFAIL));
}
}
//
// XServiceInfo
//
OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
{
return OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDTARGET_IMPL_NAME));
}
sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException)
{
return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM( OS2_DNDTARGET_SERVICE_NAME)));
}
Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException)
{
OUString names[1]= {OUString(RTL_CONSTASCII_USTRINGPARAM( OS2_DNDTARGET_SERVICE_NAME))};
return Sequence<OUString>(names, 1);
}
//
// AOO private interface events
//
void DropTarget::fire_drop( const DropTargetDropEvent& dte)
{
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
if( pContainer)
{
OInterfaceIteratorHelper iter( *pContainer);
while( iter.hasMoreElements())
{
uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
try { listener->drop( dte); }
catch(RuntimeException&) {}
}
}
debug_printf("DropTarget::fire_drop fired");
}
void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
{
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
if( pContainer)
{
OInterfaceIteratorHelper iter( *pContainer);
while( iter.hasMoreElements())
{
uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
try { listener->dragEnter( e); }
catch (RuntimeException&) {}
}
}
debug_printf("DropTarget::fire_dragEnter fired");
}
void DropTarget::fire_dragExit(const DropTargetEvent& dte)
{
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
if( pContainer)
{
OInterfaceIteratorHelper iter( *pContainer);
while( iter.hasMoreElements())
{
uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
try { listener->dragExit( dte); }
catch (RuntimeException&) {}
}
}
debug_printf("DropTarget::fire_dragExit fired");
}
void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
{
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
if( pContainer)
{
OInterfaceIteratorHelper iter( *pContainer );
while( iter.hasMoreElements())
{
uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
try { listener->dragOver( dtde); }
catch (RuntimeException&) {}
}
}
debug_printf("DropTarget::fire_dragOver fired");
}
void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
{
OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
if( pContainer)
{
OInterfaceIteratorHelper iter( *pContainer);
while( iter.hasMoreElements())
{
uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
try { listener->dropActionChanged( dtde); }
catch (RuntimeException&) {}
}
}
debug_printf("DropTarget::fire_dropActionChanged fired");
}
//
// OS/2 specific platform code
//
MRESULT DropTarget::dragEnter( PDRAGINFO dragInfo)
{
debug_printf("DropTarget::dragEnter start hwnd 0x%x", m_hWnd);
// disable drag enter emulation until next DM_DRAGLEAVE
dragEnterEmulation = false;
// Get access to the DRAGINFO data structure
DrgAccessDraginfo( dragInfo);
// Initially when DnD will be started no modifier key can be pressed yet
// thus we are getting all actions that the drag source supports, we save
// this value because later the system masks the drag source actions if
// a modifier key will be pressed
mDragSourceSupportedActions =
SystemToOfficeDragActions( dragInfo->usOperation);
// Only if the drop target is really interested in the drag actions
// supported by the source
if (mDragSourceSupportedActions & mDefaultActions) {
//sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender);
sal_Int8 currentAction = mDragSourceSupportedActions;
// map from desktop to client window
MapWindowPoint( m_hWnd, dragInfo, &ptlMouse);
// This will free the previous instance if present,
// so it removes the tmp file
mXTransferable = Reference<XTransferable>();
// if g_XTransferable is empty this is an external drop operation,
// create a new transferable set
mXTransferable = DragSource::g_XTransferable;
if (!mXTransferable.is()) {
mXTransferable =
//new OTransferable( OUString::createFromAscii( "TestString" ) );
new OTransferable( m_hWnd, dragInfo);
}
#if 1
// dump data flavours
Sequence<DataFlavor> seq = mXTransferable->getTransferDataFlavors();
for( int i=0; i<seq.getLength(); i++) {
DataFlavor df = seq[i];
debug_printf("DropTarget::dragEnter mimetype %s",
::rtl::OUStringToOString( df.MimeType, RTL_TEXTENCODING_UTF8 ).getStr());
}
#endif
debug_printf("DropTarget::dragEnter (%dx%d) mDragSourceSupportedActions %d",
ptlMouse.x, ptlMouse.y,
mDragSourceSupportedActions);
DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this),
0, this, currentAction,
ptlMouse.x, ptlMouse.y,
mDragSourceSupportedActions,
mXTransferable->getTransferDataFlavors());
fire_dragEnter(dtdee);
}
// Release the draginfo data structure
DrgFreeDraginfo(dragInfo);
return OfficeToSystemDragActions( mSelectedDropAction);
}
MRESULT DropTarget::dragOver( PDRAGINFO dragInfo)
{
MRESULT dragOp = MRFROM2SHORT( DOR_NODROPOP, 0);
if (dragEnterEmulation)
return dragEnter( dragInfo);
// Get access to the DRAGINFO data structure
DrgAccessDraginfo( dragInfo);
sal_Int8 currentDragSourceActions =
SystemToOfficeDragActions( dragInfo->usOperation);
// Only if the drop target is really interessted in the drag actions
// supported by the source
if (currentDragSourceActions & mDefaultActions) {
//sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender);
sal_Int8 currentAction = currentDragSourceActions;
// map from desktop to client window
MapWindowPoint( m_hWnd, dragInfo, &ptlMouse);
DropTargetDragEvent dtde(static_cast<OWeakObject*>(this),
0, this, currentAction,
ptlMouse.x, ptlMouse.y,
mDragSourceSupportedActions);
// firing the event will result in a XDropTargetDragContext event
fire_dragOver(dtde);
dragOp = OfficeToSystemDragActions(mSelectedDropAction);
}
// Release the draginfo data structure
DrgFreeDraginfo(dragInfo);
return dragOp;
}
MRESULT DropTarget::dragLeave( PDRAGINFO /* dragInfo */)
{
debug_printf("DropTarget::dragLeave");
DropTargetEvent dte(static_cast<OWeakObject*>(this), 0);
fire_dragExit(dte);
// reset action flags
mDragSourceSupportedActions = ACTION_NONE;
mSelectedDropAction = ACTION_NONE;
// enable drag enter emulation again
dragEnterEmulation = true;
// free local transferable list on next d&d or destruction
return 0;
}
MRESULT DropTarget::drop( PDRAGINFO dragInfo)
{
debug_printf("DropTarget::drop");
// Get access to the DRAGINFO data structure
DrgAccessDraginfo( dragInfo);
MRESULT dropOp = MRFROM2SHORT( DOR_NODROPOP, 0);
if (mSelectedDropAction != ACTION_NONE) {
bool rr = false;
// map from desktop to client window
MapWindowPoint( m_hWnd, dragInfo, &ptlMouse);
// if external d&d, request rendering
OTransferable* ot = dynamic_cast<OTransferable*>(mXTransferable.get());
if (ot != NULL) {
// request rendering, if operation is already possible it
// will return false
rr = ot->requestRendering();
debug_printf("DropTarget::drop requestRendering=%d", rr);
}
// no rendering requested, post a DM_RENDERCOMPLETE to ourselves
// to fire AOO drop event
if (rr == false)
WinPostMsg( m_hWnd, DM_RENDERCOMPLETE, 0, 0);
dropOp = OfficeToSystemDragActions(mSelectedDropAction);
}
// Release the draginfo data structure
DrgFreeDraginfo(dragInfo);
return dropOp;
}
MRESULT DropTarget::renderComplete( PDRAGTRANSFER dragTransfer)
{
debug_printf("DropTarget::renderComplete dragTransfer 0x%x", dragTransfer);
if (dragTransfer != NULL) {
OTransferable* ot = dynamic_cast<OTransferable*>(mXTransferable.get());
// DM_RENDERCOMPLETE cannot be received in internal AOO d&d
if (ot == NULL) {
debug_printf("DropTarget::renderComplete INTERNAL ERROR null dragtransfer");
return 0;
}
// set rendered data
ot->renderComplete( dragTransfer);
}
debug_printf("DropTarget::renderComplete mXTransferable.is() %d", mXTransferable.is());
// complete AOO drop event, this will make AOO call
// XTransferable::getTransferData() for external ops,
// then acceptDrop(), dropComplete() are called from listeners
DropTargetDropEvent dtde( static_cast<OWeakObject*>(this),
0, this, mSelectedDropAction,
ptlMouse.x, ptlMouse.y,
mDragSourceSupportedActions,
mXTransferable);
fire_drop(dtde);
// Reserved value, should be 0
return 0;
}