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