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