xref: /trunk/main/dtrans/source/os2/dnd/DropTarget.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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