/************************************************************** * * 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 #include #include #include #include #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& 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(); 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(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& dtl) throw(RuntimeException) { debug_printf("DropTarget::addDropTargetListener hwnd %x", m_hWnd); rBHelper.addListener(::getCppuType(&dtl), dtl); } void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference& 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(names, 1); } // // AOO private interface events // void DropTarget::fire_drop( const DropTargetDropEvent& dte) { OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( 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* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( 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* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( 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* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer ); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( 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* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( 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(); // 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 seq = mXTransferable->getTransferDataFlavors(); for( int i=0; i(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(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(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(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(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(this), 0, this, mSelectedDropAction, ptlMouse.x, ptlMouse.y, mDragSourceSupportedActions, mXTransferable); fire_drop(dtde); // Reserved value, should be 0 return 0; }