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