| /************************************************************** |
| * |
| * 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; |
| } |