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