1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_dtrans.hxx" 24 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> 25 #include <com/sun/star/datatransfer/XTransferable.hpp> 26 #include <rtl/ustring.h> 27 #include <cppuhelper/implbase1.hxx> 28 29 #include <vcl/window.hxx> 30 31 #include "globals.hxx" 32 #include "DropTarget.hxx" 33 #include "DragSource.hxx" 34 #include "OTransferable.hxx" 35 36 37 using namespace com::sun::star; 38 using namespace com::sun::star::io; 39 using namespace com::sun::star::datatransfer::dnd::DNDConstants; 40 41 42 DropTarget::DropTarget( const Reference<XMultiServiceFactory>& sf): 43 WeakComponentImplHelper5< XInitialization, 44 XDropTarget, 45 XDropTargetDragContext, 46 XDropTargetDropContext, 47 XServiceInfo>(m_aMutex), 48 m_serviceFactory( sf), 49 dragEnterEmulation( true), 50 mbActive(false), 51 mDragSourceSupportedActions(ACTION_NONE), 52 mSelectedDropAction(ACTION_NONE), 53 mDefaultActions(ACTION_COPY_OR_MOVE | ACTION_LINK | ACTION_DEFAULT) 54 { 55 g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt ); 56 } 57 58 DropTarget::~DropTarget() 59 { 60 debug_printf("DropTarget::~DropTarget"); 61 62 // This will free the previous instance if present, 63 // so it removes the tmp file 64 mXTransferable = Reference<XTransferable>(); 65 66 g_moduleCount.modCnt.release( &g_moduleCount.modCnt ); 67 } 68 69 void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments) 70 throw(Exception) 71 { 72 if (aArguments.getLength() < 2) { 73 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")), 74 static_cast<OWeakObject*>(this)); 75 } 76 77 m_hWnd = *(HWND*) aArguments[0].getValue(); 78 debug_printf("DropTarget::initialize hwnd %x", m_hWnd); 79 80 // subclass window to allow intercepting D&D messages 81 defWndProc = WinSubclassWindow( m_hWnd, dndFrameProc); 82 SetWindowDropTargetPtr( m_hWnd, this); 83 } 84 85 // called from WeakComponentImplHelperX::dispose 86 // WeakComponentImplHelper calls disposing before it destroys 87 // itself. 88 void SAL_CALL DropTarget::disposing() 89 { 90 debug_printf("DropTarget::disposing hwnd %x", m_hWnd); 91 92 // revert window subclassing 93 WinSubclassWindow( m_hWnd, defWndProc); 94 defWndProc = NULL; 95 SetWindowDropTargetPtr( m_hWnd, 0); 96 } 97 98 void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl) 99 throw(RuntimeException) 100 { 101 debug_printf("DropTarget::addDropTargetListener hwnd %x", m_hWnd); 102 rBHelper.addListener(::getCppuType(&dtl), dtl); 103 } 104 105 void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl) 106 throw(RuntimeException) 107 { 108 debug_printf("DropTarget::removeDropTargetListener hwnd %x", m_hWnd); 109 rBHelper.removeListener(::getCppuType(&dtl), dtl); 110 } 111 112 sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException) 113 { 114 debug_printf("DropTarget::isActive %d", mbActive); 115 return mbActive; 116 } 117 118 void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException) 119 { 120 debug_printf("DropTarget::setActive %d", active); 121 mbActive = active; 122 } 123 124 sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException) 125 { 126 debug_printf("DropTarget::getDefaultActions %d", mDefaultActions); 127 return mDefaultActions; 128 } 129 130 void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException) 131 { 132 OSL_ENSURE( actions < 8, "No valid default actions"); 133 mDefaultActions= actions; 134 } 135 136 // 137 // XDropTargetDragContext 138 // 139 // Non - interface functions ============================================================ 140 // DropTarget fires events to XDropTargetListeners. The event object can contains an 141 // XDropTargetDragContext implementation. When the listener calls on that interface 142 // then the calls are delegated from DragContext (XDropTargetDragContext) to these 143 // functions. 144 // Only one listener which visible area is affected is allowed to call on 145 // XDropTargetDragContext 146 147 void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException) 148 { 149 debug_printf("DropTarget::acceptDrag hwnd %x, dragOperation %d", m_hWnd, dragOperation); 150 mSelectedDropAction = dragOperation; 151 } 152 153 void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException) 154 { 155 debug_printf("DropTarget::rejectDrag hwnd %x", m_hWnd); 156 mSelectedDropAction = ACTION_NONE; 157 } 158 159 // 160 // XDropTargetDropContext 161 // 162 // Non - interface functions ============================================================ 163 // DropTarget fires events to XDropTargetListeners. The event object contains an 164 // XDropTargetDropContext implementation. When the listener calls on that interface 165 // then the calls are delegated from DropContext (XDropTargetDropContext) to these 166 // functions. 167 // Only one listener which visible area is affected is allowed to call on 168 // XDropTargetDropContext 169 // Returning sal_False would cause the XDropTargetDropContext or ..DragContext implementation 170 // to throw an InvalidDNDOperationException, meaning that a Drag is not currently performed. 171 // return sal_False results in throwing a InvalidDNDOperationException in the caller. 172 // 173 void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException) 174 { 175 debug_printf("DropTarget::acceptDrop hwnd %x, dragOperation %d", m_hWnd, dropOperation); 176 mSelectedDropAction = dropOperation; 177 } 178 179 void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException) 180 { 181 debug_printf("DropTarget::rejectDrop hwnd %x", m_hWnd); 182 mSelectedDropAction = ACTION_NONE; 183 } 184 185 void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException) 186 { 187 debug_printf("DropTarget::dropComplete hwnd %x", m_hWnd); 188 189 // reset action flags 190 mDragSourceSupportedActions = ACTION_NONE; 191 mSelectedDropAction = ACTION_NONE; 192 // enable drag enter emulation again 193 dragEnterEmulation = true; 194 // free local transferable list on next d&d or destruction 195 196 // post a dummy message to source window to allow DragSource 197 // release resources and close internal d&d 198 if (DragSource::g_DragSourceHwnd != NULLHANDLE) { 199 debug_printf("DropTarget::renderComplete post DM_AOO_ENDCONVERSATION to source"); 200 WinPostMsg( DragSource::g_DragSourceHwnd, DM_AOO_ENDCONVERSATION, 0, 201 MPFROMSHORT(success ? DMFL_TARGETSUCCESSFUL : DMFL_TARGETFAIL)); 202 } 203 204 } 205 206 // 207 // XServiceInfo 208 // 209 OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException) 210 { 211 return OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDTARGET_IMPL_NAME)); 212 } 213 214 sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException) 215 { 216 return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM( OS2_DNDTARGET_SERVICE_NAME))); 217 } 218 219 Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException) 220 { 221 OUString names[1]= {OUString(RTL_CONSTASCII_USTRINGPARAM( OS2_DNDTARGET_SERVICE_NAME))}; 222 return Sequence<OUString>(names, 1); 223 } 224 225 // 226 // AOO private interface events 227 // 228 void DropTarget::fire_drop( const DropTargetDropEvent& dte) 229 { 230 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 231 if( pContainer) 232 { 233 OInterfaceIteratorHelper iter( *pContainer); 234 while( iter.hasMoreElements()) 235 { 236 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 237 238 try { listener->drop( dte); } 239 catch(RuntimeException&) {} 240 } 241 } 242 debug_printf("DropTarget::fire_drop fired"); 243 } 244 245 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) 246 { 247 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 248 if( pContainer) 249 { 250 OInterfaceIteratorHelper iter( *pContainer); 251 while( iter.hasMoreElements()) 252 { 253 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 254 255 try { listener->dragEnter( e); } 256 catch (RuntimeException&) {} 257 } 258 } 259 debug_printf("DropTarget::fire_dragEnter fired"); 260 } 261 262 void DropTarget::fire_dragExit(const DropTargetEvent& dte) 263 { 264 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 265 266 if( pContainer) 267 { 268 OInterfaceIteratorHelper iter( *pContainer); 269 while( iter.hasMoreElements()) 270 { 271 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 272 273 try { listener->dragExit( dte); } 274 catch (RuntimeException&) {} 275 } 276 } 277 debug_printf("DropTarget::fire_dragExit fired"); 278 } 279 280 void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) 281 { 282 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 283 if( pContainer) 284 { 285 OInterfaceIteratorHelper iter( *pContainer ); 286 while( iter.hasMoreElements()) 287 { 288 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 289 290 try { listener->dragOver( dtde); } 291 catch (RuntimeException&) {} 292 } 293 } 294 debug_printf("DropTarget::fire_dragOver fired"); 295 } 296 297 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) 298 { 299 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 300 if( pContainer) 301 { 302 OInterfaceIteratorHelper iter( *pContainer); 303 while( iter.hasMoreElements()) 304 { 305 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 306 307 try { listener->dropActionChanged( dtde); } 308 catch (RuntimeException&) {} 309 } 310 } 311 debug_printf("DropTarget::fire_dropActionChanged fired"); 312 } 313 314 // 315 // OS/2 specific platform code 316 // 317 318 MRESULT DropTarget::dragEnter( PDRAGINFO dragInfo) 319 { 320 debug_printf("DropTarget::dragEnter start hwnd 0x%x", m_hWnd); 321 322 // disable drag enter emulation until next DM_DRAGLEAVE 323 dragEnterEmulation = false; 324 325 // Get access to the DRAGINFO data structure 326 DrgAccessDraginfo( dragInfo); 327 328 // Initially when DnD will be started no modifier key can be pressed yet 329 // thus we are getting all actions that the drag source supports, we save 330 // this value because later the system masks the drag source actions if 331 // a modifier key will be pressed 332 mDragSourceSupportedActions = 333 SystemToOfficeDragActions( dragInfo->usOperation); 334 335 // Only if the drop target is really interested in the drag actions 336 // supported by the source 337 if (mDragSourceSupportedActions & mDefaultActions) { 338 339 //sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender); 340 sal_Int8 currentAction = mDragSourceSupportedActions; 341 342 // map from desktop to client window 343 MapWindowPoint( m_hWnd, dragInfo, &ptlMouse); 344 345 // This will free the previous instance if present, 346 // so it removes the tmp file 347 mXTransferable = Reference<XTransferable>(); 348 349 // if g_XTransferable is empty this is an external drop operation, 350 // create a new transferable set 351 mXTransferable = DragSource::g_XTransferable; 352 if (!mXTransferable.is()) { 353 mXTransferable = 354 //new OTransferable( OUString::createFromAscii( "TestString" ) ); 355 new OTransferable( m_hWnd, dragInfo); 356 } 357 358 #if 1 359 // dump data flavours 360 Sequence<DataFlavor> seq = mXTransferable->getTransferDataFlavors(); 361 for( int i=0; i<seq.getLength(); i++) { 362 DataFlavor df = seq[i]; 363 debug_printf("DropTarget::dragEnter mimetype %s", 364 ::rtl::OUStringToOString( df.MimeType, RTL_TEXTENCODING_UTF8 ).getStr()); 365 } 366 #endif 367 368 debug_printf("DropTarget::dragEnter (%dx%d) mDragSourceSupportedActions %d", 369 ptlMouse.x, ptlMouse.y, 370 mDragSourceSupportedActions); 371 372 DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this), 373 0, this, currentAction, 374 ptlMouse.x, ptlMouse.y, 375 mDragSourceSupportedActions, 376 mXTransferable->getTransferDataFlavors()); 377 fire_dragEnter(dtdee); 378 } 379 380 // Release the draginfo data structure 381 DrgFreeDraginfo(dragInfo); 382 383 return OfficeToSystemDragActions( mSelectedDropAction); 384 } 385 386 MRESULT DropTarget::dragOver( PDRAGINFO dragInfo) 387 { 388 MRESULT dragOp = MRFROM2SHORT( DOR_NODROPOP, 0); 389 390 if (dragEnterEmulation) 391 return dragEnter( dragInfo); 392 393 // Get access to the DRAGINFO data structure 394 DrgAccessDraginfo( dragInfo); 395 396 sal_Int8 currentDragSourceActions = 397 SystemToOfficeDragActions( dragInfo->usOperation); 398 399 // Only if the drop target is really interested in the drag actions 400 // supported by the source 401 if (currentDragSourceActions & mDefaultActions) { 402 //sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender); 403 sal_Int8 currentAction = currentDragSourceActions; 404 405 // map from desktop to client window 406 MapWindowPoint( m_hWnd, dragInfo, &ptlMouse); 407 408 DropTargetDragEvent dtde(static_cast<OWeakObject*>(this), 409 0, this, currentAction, 410 ptlMouse.x, ptlMouse.y, 411 mDragSourceSupportedActions); 412 // firing the event will result in a XDropTargetDragContext event 413 fire_dragOver(dtde); 414 415 dragOp = OfficeToSystemDragActions(mSelectedDropAction); 416 } 417 418 // Release the draginfo data structure 419 DrgFreeDraginfo(dragInfo); 420 return dragOp; 421 } 422 423 MRESULT DropTarget::dragLeave( PDRAGINFO /* dragInfo */) 424 { 425 debug_printf("DropTarget::dragLeave"); 426 427 DropTargetEvent dte(static_cast<OWeakObject*>(this), 0); 428 fire_dragExit(dte); 429 430 // reset action flags 431 mDragSourceSupportedActions = ACTION_NONE; 432 mSelectedDropAction = ACTION_NONE; 433 // enable drag enter emulation again 434 dragEnterEmulation = true; 435 // free local transferable list on next d&d or destruction 436 437 return 0; 438 } 439 440 MRESULT DropTarget::drop( PDRAGINFO dragInfo) 441 { 442 debug_printf("DropTarget::drop"); 443 444 // Get access to the DRAGINFO data structure 445 DrgAccessDraginfo( dragInfo); 446 447 MRESULT dropOp = MRFROM2SHORT( DOR_NODROPOP, 0); 448 449 if (mSelectedDropAction != ACTION_NONE) { 450 451 bool rr = false; 452 453 // map from desktop to client window 454 MapWindowPoint( m_hWnd, dragInfo, &ptlMouse); 455 456 // if external d&d, request rendering 457 OTransferable* ot = dynamic_cast<OTransferable*>(mXTransferable.get()); 458 if (ot != NULL) { 459 // request rendering, if operation is already possible it 460 // will return false 461 rr = ot->requestRendering(); 462 debug_printf("DropTarget::drop requestRendering=%d", rr); 463 } 464 465 // no rendering requested, post a DM_RENDERCOMPLETE to ourselves 466 // to fire AOO drop event 467 if (rr == false) 468 WinPostMsg( m_hWnd, DM_RENDERCOMPLETE, 0, 0); 469 470 dropOp = OfficeToSystemDragActions(mSelectedDropAction); 471 } 472 473 // Release the draginfo data structure 474 DrgFreeDraginfo(dragInfo); 475 476 return dropOp; 477 478 } 479 480 MRESULT DropTarget::renderComplete( PDRAGTRANSFER dragTransfer) 481 { 482 debug_printf("DropTarget::renderComplete dragTransfer 0x%x", dragTransfer); 483 484 if (dragTransfer != NULL) { 485 OTransferable* ot = dynamic_cast<OTransferable*>(mXTransferable.get()); 486 // DM_RENDERCOMPLETE cannot be received in internal AOO d&d 487 if (ot == NULL) { 488 debug_printf("DropTarget::renderComplete INTERNAL ERROR null dragtransfer"); 489 return 0; 490 } 491 492 // set rendered data 493 ot->renderComplete( dragTransfer); 494 } 495 496 debug_printf("DropTarget::renderComplete mXTransferable.is() %d", mXTransferable.is()); 497 498 // complete AOO drop event, this will make AOO call 499 // XTransferable::getTransferData() for external ops, 500 // then acceptDrop(), dropComplete() are called from listeners 501 DropTargetDropEvent dtde( static_cast<OWeakObject*>(this), 502 0, this, mSelectedDropAction, 503 ptlMouse.x, ptlMouse.y, 504 mDragSourceSupportedActions, 505 mXTransferable); 506 fire_drop(dtde); 507 508 // Reserved value, should be 0 509 return 0; 510 } 511 512 /* vim: set noet sw=4 ts=4: */ 513