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