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 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.
disposing()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
addDropTargetListener(const uno::Reference<XDropTargetListener> & dtl)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
removeDropTargetListener(const uno::Reference<XDropTargetListener> & dtl)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
isActive()112 sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException)
113 {
114 debug_printf("DropTarget::isActive %d", mbActive);
115 return mbActive;
116 }
117
setActive(sal_Bool active)118 void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
119 {
120 debug_printf("DropTarget::setActive %d", active);
121 mbActive = active;
122 }
123
getDefaultActions()124 sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
125 {
126 debug_printf("DropTarget::getDefaultActions %d", mDefaultActions);
127 return mDefaultActions;
128 }
129
setDefaultActions(sal_Int8 actions)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
acceptDrag(sal_Int8 dragOperation)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
rejectDrag()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 //
acceptDrop(sal_Int8 dropOperation)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
rejectDrop()179 void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
180 {
181 debug_printf("DropTarget::rejectDrop hwnd %x", m_hWnd);
182 mSelectedDropAction = ACTION_NONE;
183 }
184
dropComplete(sal_Bool success)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 //
getImplementationName()209 OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
210 {
211 return OUString(RTL_CONSTASCII_USTRINGPARAM(OS2_DNDTARGET_IMPL_NAME));
212 }
213
supportsService(const OUString & ServiceName)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
getSupportedServiceNames()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 //
fire_drop(const DropTargetDropEvent & dte)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
fire_dragEnter(const DropTargetDragEnterEvent & e)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
fire_dragExit(const DropTargetEvent & dte)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
fire_dragOver(const DropTargetDragEvent & dtde)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
fire_dropActionChanged(const DropTargetDragEvent & dtde)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
dragEnter(PDRAGINFO dragInfo)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
dragOver(PDRAGINFO dragInfo)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
dragLeave(PDRAGINFO)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
drop(PDRAGINFO dragInfo)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
renderComplete(PDRAGTRANSFER dragTransfer)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