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
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 #include <vos/mutex.hxx>
27 #include <tools/debug.hxx>
28 #include <tools/urlobj.hxx>
29 #include <unotools/ucbstreamhelper.hxx>
30 #include <sot/exchange.hxx>
31 #include <sot/storage.hxx>
32 #include <vcl/bitmap.hxx>
33 #include <vcl/gdimtf.hxx>
34 #include <vcl/graph.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/window.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
39 #include "svl/urlbmk.hxx"
40 #include <svtools/inetimg.hxx>
41 #include <svtools/imap.hxx>
42 #include <svtools/transfer.hxx>
43
44 // --------------
45 // - Namespaces -
46 // --------------
47
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star::lang;
50 using namespace ::com::sun::star::io;
51 using namespace ::com::sun::star::datatransfer;
52 using namespace ::com::sun::star::datatransfer::clipboard;
53 using namespace ::com::sun::star::datatransfer::dnd;
54
55 // -----------------------------------------
56 // - DragSourceHelper::DragGestureListener -
57 // -----------------------------------------
58
DragGestureListener(DragSourceHelper & rDragSourceHelper)59 DragSourceHelper::DragGestureListener::DragGestureListener( DragSourceHelper& rDragSourceHelper ) :
60 mrParent( rDragSourceHelper )
61 {
62 }
63
64 // -----------------------------------------------------------------------------
65
~DragGestureListener()66 DragSourceHelper::DragGestureListener::~DragGestureListener()
67 {
68 }
69
70 // -----------------------------------------------------------------------------
71
disposing(const EventObject &)72 void SAL_CALL DragSourceHelper::DragGestureListener::disposing( const EventObject& ) throw( RuntimeException )
73 {
74 }
75
76 // -----------------------------------------------------------------------------
77
dragGestureRecognized(const DragGestureEvent & rDGE)78 void SAL_CALL DragSourceHelper::DragGestureListener::dragGestureRecognized( const DragGestureEvent& rDGE ) throw( RuntimeException )
79 {
80 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
81
82 const Point aPtPixel( rDGE.DragOriginX, rDGE.DragOriginY );
83 mrParent.StartDrag( rDGE.DragAction, aPtPixel );
84 }
85
86 // --------------------
87 // - DragSourceHelper -
88 // --------------------
89
DragSourceHelper(Window * pWindow)90 DragSourceHelper::DragSourceHelper( Window* pWindow ) :
91 mxDragGestureRecognizer( pWindow->GetDragGestureRecognizer() )
92 {
93 if( mxDragGestureRecognizer.is() )
94 {
95 mxDragGestureListener = new DragSourceHelper::DragGestureListener( *this );
96 mxDragGestureRecognizer->addDragGestureListener( mxDragGestureListener );
97 }
98 }
99
100 // -----------------------------------------------------------------------------
101
~DragSourceHelper()102 DragSourceHelper::~DragSourceHelper()
103 {
104 if( mxDragGestureRecognizer.is() )
105 mxDragGestureRecognizer->removeDragGestureListener( mxDragGestureListener );
106 }
107
108 // -----------------------------------------------------------------------------
109
StartDrag(sal_Int8,const Point &)110 void DragSourceHelper::StartDrag( sal_Int8, const Point& )
111 {
112 }
113
114 // ----------------------------------------
115 // - DropTargetHelper::DropTargetListener -
116 // ----------------------------------------
117
DropTargetListener(DropTargetHelper & rDropTargetHelper)118 DropTargetHelper::DropTargetListener::DropTargetListener( DropTargetHelper& rDropTargetHelper ) :
119 mrParent( rDropTargetHelper ),
120 mpLastDragOverEvent( NULL )
121 {
122 }
123
124 // -----------------------------------------------------------------------------
125
~DropTargetListener()126 DropTargetHelper::DropTargetListener::~DropTargetListener()
127 {
128 delete mpLastDragOverEvent;
129 }
130
131 // -----------------------------------------------------------------------------
132
disposing(const EventObject &)133 void SAL_CALL DropTargetHelper::DropTargetListener::disposing( const EventObject& ) throw( RuntimeException )
134 {
135 }
136
137 // -----------------------------------------------------------------------------
138
drop(const DropTargetDropEvent & rDTDE)139 void SAL_CALL DropTargetHelper::DropTargetListener::drop( const DropTargetDropEvent& rDTDE ) throw( RuntimeException )
140 {
141 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
142
143 try
144 {
145 AcceptDropEvent aAcceptEvent;
146 ExecuteDropEvent aExecuteEvt( rDTDE.DropAction & ~DNDConstants::ACTION_DEFAULT, Point( rDTDE.LocationX, rDTDE.LocationY ), rDTDE );
147 sal_Int8 nRet = DNDConstants::ACTION_NONE;
148
149 aExecuteEvt.mbDefault = ( ( rDTDE.DropAction & DNDConstants::ACTION_DEFAULT ) != 0 );
150
151 // in case of a default action, call ::AcceptDrop first and use the returned
152 // accepted action as the execute action in the call to ::ExecuteDrop
153 aAcceptEvent.mnAction = aExecuteEvt.mnAction;
154 aAcceptEvent.maPosPixel = aExecuteEvt.maPosPixel;
155 (DropTargetEvent&)( aAcceptEvent.maDragEvent ) = (DropTargetEvent&) rDTDE;
156 ( (DropTargetDragEvent&)( aAcceptEvent.maDragEvent ) ).DropAction = rDTDE.DropAction;
157 ( (DropTargetDragEvent&)( aAcceptEvent.maDragEvent ) ).LocationX = rDTDE.LocationX;
158 ( (DropTargetDragEvent&)( aAcceptEvent.maDragEvent ) ).LocationY = rDTDE.LocationY;
159 ( (DropTargetDragEvent&)( aAcceptEvent.maDragEvent ) ).SourceActions = rDTDE.SourceActions;
160 aAcceptEvent.mbLeaving = sal_False;
161 aAcceptEvent.mbDefault = aExecuteEvt.mbDefault;
162
163 nRet = mrParent.AcceptDrop( aAcceptEvent );
164
165 if( DNDConstants::ACTION_NONE != nRet )
166 {
167 rDTDE.Context->acceptDrop( nRet );
168
169 if( aExecuteEvt.mbDefault )
170 aExecuteEvt.mnAction = nRet;
171
172 nRet = mrParent.ExecuteDrop( aExecuteEvt );
173 }
174
175 rDTDE.Context->dropComplete( DNDConstants::ACTION_NONE != nRet );
176
177 if( mpLastDragOverEvent )
178 {
179 delete mpLastDragOverEvent;
180 mpLastDragOverEvent = NULL;
181 }
182 }
183 catch( const ::com::sun::star::uno::Exception& )
184 {
185 }
186 }
187
188 // -----------------------------------------------------------------------------
189
dragEnter(const DropTargetDragEnterEvent & rDTDEE)190 void SAL_CALL DropTargetHelper::DropTargetListener::dragEnter( const DropTargetDragEnterEvent& rDTDEE ) throw( RuntimeException )
191 {
192 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
193
194 try
195 {
196 mrParent.ImplBeginDrag( rDTDEE.SupportedDataFlavors );
197 }
198 catch( const ::com::sun::star::uno::Exception& )
199 {
200 }
201
202 dragOver( rDTDEE );
203 }
204
205 // -----------------------------------------------------------------------------
206
dragOver(const DropTargetDragEvent & rDTDE)207 void SAL_CALL DropTargetHelper::DropTargetListener::dragOver( const DropTargetDragEvent& rDTDE ) throw( RuntimeException )
208 {
209 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
210
211 try
212 {
213 if( mpLastDragOverEvent )
214 delete mpLastDragOverEvent;
215
216 mpLastDragOverEvent = new AcceptDropEvent( rDTDE.DropAction & ~DNDConstants::ACTION_DEFAULT, Point( rDTDE.LocationX, rDTDE.LocationY ), rDTDE );
217 mpLastDragOverEvent->mbDefault = ( ( rDTDE.DropAction & DNDConstants::ACTION_DEFAULT ) != 0 );
218
219 const sal_Int8 nRet = mrParent.AcceptDrop( *mpLastDragOverEvent );
220
221 if( DNDConstants::ACTION_NONE == nRet )
222 rDTDE.Context->rejectDrag();
223 else
224 rDTDE.Context->acceptDrag( nRet );
225 }
226 catch( const ::com::sun::star::uno::Exception& )
227 {
228 }
229 }
230
231 // -----------------------------------------------------------------------------
232
dragExit(const DropTargetEvent &)233 void SAL_CALL DropTargetHelper::DropTargetListener::dragExit( const DropTargetEvent& ) throw( RuntimeException )
234 {
235 const ::vos::OGuard aGuard( Application::GetSolarMutex() );
236
237 try
238 {
239 if( mpLastDragOverEvent )
240 {
241 mpLastDragOverEvent->mbLeaving = sal_True;
242 mrParent.AcceptDrop( *mpLastDragOverEvent );
243 delete mpLastDragOverEvent;
244 mpLastDragOverEvent = NULL;
245 }
246
247 mrParent.ImplEndDrag();
248 }
249 catch( const ::com::sun::star::uno::Exception& )
250 {
251 }
252 }
253
254
255 // -----------------------------------------------------------------------------
256
dropActionChanged(const DropTargetDragEvent &)257 void SAL_CALL DropTargetHelper::DropTargetListener::dropActionChanged( const DropTargetDragEvent& ) throw( RuntimeException )
258 {
259 }
260
261 // --------------------
262 // - DropTargetHelper -
263 // --------------------
264
DropTargetHelper(Window * pWindow)265 DropTargetHelper::DropTargetHelper( Window* pWindow ) :
266 mxDropTarget( pWindow->GetDropTarget() ),
267 mpFormats( new DataFlavorExVector )
268 {
269 ImplConstruct();
270 }
271
272 // -----------------------------------------------------------------------------
273
DropTargetHelper(const Reference<XDropTarget> & rxDropTarget)274 DropTargetHelper::DropTargetHelper( const Reference< XDropTarget >& rxDropTarget ) :
275 mxDropTarget( rxDropTarget ),
276 mpFormats( new DataFlavorExVector )
277 {
278 ImplConstruct();
279 }
280
281 // -----------------------------------------------------------------------------
282
~DropTargetHelper()283 DropTargetHelper::~DropTargetHelper()
284 {
285 if( mxDropTarget.is() )
286 mxDropTarget->removeDropTargetListener( mxDropTargetListener );
287
288 delete mpFormats;
289 }
290
291 // -----------------------------------------------------------------------------
292
ImplConstruct()293 void DropTargetHelper::ImplConstruct()
294 {
295 if( mxDropTarget.is() )
296 {
297 mxDropTargetListener = new DropTargetHelper::DropTargetListener( *this );
298 mxDropTarget->addDropTargetListener( mxDropTargetListener );
299 mxDropTarget->setActive( sal_True );
300 }
301 }
302
303 // -----------------------------------------------------------------------------
304
ImplBeginDrag(const Sequence<DataFlavor> & rSupportedDataFlavors)305 void DropTargetHelper::ImplBeginDrag( const Sequence< DataFlavor >& rSupportedDataFlavors )
306 {
307 mpFormats->clear();
308 TransferableDataHelper::FillDataFlavorExVector( rSupportedDataFlavors, *mpFormats );
309 }
310
311 // -----------------------------------------------------------------------------
312
ImplEndDrag()313 void DropTargetHelper::ImplEndDrag()
314 {
315 mpFormats->clear();
316 }
317
318 // -----------------------------------------------------------------------------
319
AcceptDrop(const AcceptDropEvent &)320 sal_Int8 DropTargetHelper::AcceptDrop( const AcceptDropEvent& )
321 {
322 return( DNDConstants::ACTION_NONE );
323 }
324
325 // -----------------------------------------------------------------------------
326
ExecuteDrop(const ExecuteDropEvent &)327 sal_Int8 DropTargetHelper::ExecuteDrop( const ExecuteDropEvent& )
328 {
329 return( DNDConstants::ACTION_NONE );
330 }
331
332 // -----------------------------------------------------------------------------
333
IsDropFormatSupported(SotFormatStringId nFormat)334 sal_Bool DropTargetHelper::IsDropFormatSupported( SotFormatStringId nFormat )
335 {
336 DataFlavorExVector::iterator aIter( mpFormats->begin() ), aEnd( mpFormats->end() );
337 sal_Bool bRet = sal_False;
338
339 while( aIter != aEnd )
340 {
341 if( nFormat == (*aIter++).mnSotId )
342 {
343 bRet = sal_True;
344 aIter = aEnd;
345 }
346 }
347
348 return bRet;
349 }
350
351 // -----------------------------------------------------------------------------
352
IsDropFormatSupported(const DataFlavor & rFlavor)353 sal_Bool DropTargetHelper::IsDropFormatSupported( const DataFlavor& rFlavor )
354 {
355 DataFlavorExVector::iterator aIter( mpFormats->begin() ), aEnd( mpFormats->end() );
356 sal_Bool bRet = sal_False;
357
358 while( aIter != aEnd )
359 {
360 if( TransferableDataHelper::IsEqual( rFlavor, *aIter++ ) )
361 {
362 bRet = sal_True;
363 aIter = aEnd;
364 }
365 }
366
367 return bRet;
368 }
369
370 // -----------------------------------------------------------------------------
371 // TransferDataContainer
372 // -----------------------------------------------------------------------------
373
374 struct TDataCntnrEntry_Impl
375 {
376 ::com::sun::star::uno::Any aAny;
377 SotFormatStringId nId;
378 };
379
380 // -----------------------------------------------------------------------------
381
382 typedef ::std::list< TDataCntnrEntry_Impl > TDataCntnrEntryList;
383
384 // -----------------------------------------------------------------------------
385
386 struct TransferDataContainer_Impl
387 {
388 TDataCntnrEntryList aFmtList;
389 Link aFinshedLnk;
390 INetBookmark* pBookmk;
391 Graphic* pGrf;
392
TransferDataContainer_ImplTransferDataContainer_Impl393 TransferDataContainer_Impl()
394 : pBookmk( 0 ), pGrf( 0 )
395 {
396 }
397
~TransferDataContainer_ImplTransferDataContainer_Impl398 ~TransferDataContainer_Impl()
399 {
400 delete pBookmk;
401 delete pGrf;
402 }
403 };
404
405 // -----------------------------------------------------------------------------
406
TransferDataContainer()407 TransferDataContainer::TransferDataContainer()
408 : pImpl( new TransferDataContainer_Impl )
409 {
410 }
411
412 // -----------------------------------------------------------------------------
413
~TransferDataContainer()414 TransferDataContainer::~TransferDataContainer()
415 {
416 delete pImpl;
417 }
418
419 // -----------------------------------------------------------------------------
420
AddSupportedFormats()421 void TransferDataContainer::AddSupportedFormats()
422 {
423 }
424
425 // -----------------------------------------------------------------------------
426
GetData(const::com::sun::star::datatransfer::DataFlavor & rFlavor)427 sal_Bool TransferDataContainer::GetData( const
428 ::com::sun::star::datatransfer::DataFlavor& rFlavor )
429 {
430 TDataCntnrEntryList::iterator aIter( pImpl->aFmtList.begin() ),
431 aEnd( pImpl->aFmtList.end() );
432 sal_Bool bFnd = sal_False;
433 sal_uLong nFmtId = SotExchange::GetFormat( rFlavor );
434
435 // test first the list
436 for( ; aIter != aEnd; ++aIter )
437 {
438 TDataCntnrEntry_Impl& rEntry = (TDataCntnrEntry_Impl&)*aIter;
439 if( nFmtId == rEntry.nId )
440 {
441 bFnd = SetAny( rEntry.aAny, rFlavor );
442 break;
443 }
444 }
445
446 // test second the bookmark pointer
447 if( !bFnd )
448 switch( nFmtId )
449 {
450 case SOT_FORMAT_STRING:
451 case SOT_FORMATSTR_ID_SOLK:
452 case SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK:
453 case SOT_FORMATSTR_ID_FILECONTENT:
454 case SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR:
455 case SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR:
456 if( pImpl->pBookmk )
457 bFnd = SetINetBookmark( *pImpl->pBookmk, rFlavor );
458 break;
459
460 case SOT_FORMATSTR_ID_SVXB:
461 case SOT_FORMATSTR_ID_PNG:
462 case SOT_FORMAT_BITMAP:
463 case SOT_FORMAT_GDIMETAFILE:
464 if( pImpl->pGrf )
465 bFnd = SetGraphic( *pImpl->pGrf, rFlavor );
466 break;
467 }
468
469 return bFnd;
470 }
471
472 // -----------------------------------------------------------------------------
473
ClearData()474 void TransferDataContainer::ClearData()
475 {
476 delete pImpl;
477 pImpl = new TransferDataContainer_Impl;
478 ClearFormats();
479 }
480
481 // -----------------------------------------------------------------------------
482
CopyINetBookmark(const INetBookmark & rBkmk)483 void TransferDataContainer::CopyINetBookmark( const INetBookmark& rBkmk )
484 {
485 if( !pImpl->pBookmk )
486 pImpl->pBookmk = new INetBookmark( rBkmk );
487 else
488 *pImpl->pBookmk = rBkmk;
489
490 AddFormat( SOT_FORMAT_STRING );
491 AddFormat( SOT_FORMATSTR_ID_SOLK );
492 AddFormat( SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK );
493 AddFormat( SOT_FORMATSTR_ID_FILECONTENT );
494 AddFormat( SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR );
495 AddFormat( SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR );
496 }
497
498 // -----------------------------------------------------------------------------
499
CopyAnyData(sal_uLong nFormatId,const sal_Char * pData,sal_uLong nLen)500 void TransferDataContainer::CopyAnyData( sal_uLong nFormatId,
501 const sal_Char* pData, sal_uLong nLen )
502 {
503 if( nLen )
504 {
505 TDataCntnrEntry_Impl aEntry;
506 aEntry.nId = nFormatId;
507
508 Sequence< sal_Int8 > aSeq( nLen );
509 memcpy( aSeq.getArray(), pData, nLen );
510 aEntry.aAny <<= aSeq;
511 pImpl->aFmtList.push_back( aEntry );
512 AddFormat( nFormatId );
513 }
514 }
515
516 // -----------------------------------------------------------------------------
517
CopyByteString(sal_uLong nFormatId,const ByteString & rStr)518 void TransferDataContainer::CopyByteString( sal_uLong nFormatId,
519 const ByteString& rStr )
520 {
521 CopyAnyData( nFormatId, rStr.GetBuffer(), rStr.Len() );
522 }
523
524 // -----------------------------------------------------------------------------
525
CopyINetImage(const INetImage & rINtImg)526 void TransferDataContainer::CopyINetImage( const INetImage& rINtImg )
527 {
528 SvMemoryStream aMemStm( 1024, 1024 );
529 aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
530 rINtImg.Write( aMemStm, SOT_FORMATSTR_ID_INET_IMAGE );
531 CopyAnyData( SOT_FORMATSTR_ID_INET_IMAGE, (sal_Char*)aMemStm.GetData(),
532 aMemStm.Seek( STREAM_SEEK_TO_END ) );
533 }
534
535 // -----------------------------------------------------------------------------
536
CopyImageMap(const ImageMap & rImgMap)537 void TransferDataContainer::CopyImageMap( const ImageMap& rImgMap )
538 {
539 SvMemoryStream aMemStm( 8192, 8192 );
540 aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
541 rImgMap.Write( aMemStm, String() );
542 CopyAnyData( SOT_FORMATSTR_ID_SVIM, (sal_Char*)aMemStm.GetData(),
543 aMemStm.Seek( STREAM_SEEK_TO_END ) );
544 }
545
546 // -----------------------------------------------------------------------------
547
CopyGraphic(const Graphic & rGrf)548 void TransferDataContainer::CopyGraphic( const Graphic& rGrf )
549 {
550 GraphicType nType = rGrf.GetType();
551 if( GRAPHIC_NONE != nType )
552 {
553 if( !pImpl->pGrf )
554 pImpl->pGrf = new Graphic( rGrf );
555 else
556 *pImpl->pGrf = rGrf;
557
558 AddFormat( SOT_FORMATSTR_ID_SVXB );
559
560 if( GRAPHIC_BITMAP == nType )
561 {
562 AddFormat( SOT_FORMATSTR_ID_PNG );
563 AddFormat( SOT_FORMAT_BITMAP );
564 }
565 else if( GRAPHIC_GDIMETAFILE == nType )
566 {
567 AddFormat( SOT_FORMAT_GDIMETAFILE );
568 }
569 }
570 }
571
572 // -----------------------------------------------------------------------------
573
CopyString(sal_uInt16 nFmt,const String & rStr)574 void TransferDataContainer::CopyString( sal_uInt16 nFmt, const String& rStr )
575 {
576 if( rStr.Len() )
577 {
578 TDataCntnrEntry_Impl aEntry;
579 aEntry.nId = nFmt;
580 rtl::OUString aStr( rStr );
581 aEntry.aAny <<= aStr;
582 pImpl->aFmtList.push_back( aEntry );
583 AddFormat( aEntry.nId );
584 }
585 }
586
587 // -----------------------------------------------------------------------------
588
CopyString(const String & rStr)589 void TransferDataContainer::CopyString( const String& rStr )
590 {
591 CopyString( SOT_FORMAT_STRING, rStr );
592 }
593
594 // -----------------------------------------------------------------------------
595
CopyAny(sal_uInt16 nFmt,const::com::sun::star::uno::Any & rAny)596 void TransferDataContainer::CopyAny( sal_uInt16 nFmt,
597 const ::com::sun::star::uno::Any& rAny )
598 {
599 TDataCntnrEntry_Impl aEntry;
600 aEntry.nId = nFmt;
601 aEntry.aAny = rAny;
602 pImpl->aFmtList.push_back( aEntry );
603 AddFormat( aEntry.nId );
604 }
605
606 // -----------------------------------------------------------------------------
607
HasAnyData() const608 sal_Bool TransferDataContainer::HasAnyData() const
609 {
610 return pImpl->aFmtList.begin() != pImpl->aFmtList.end() ||
611 0 != pImpl->pBookmk;
612 }
613
614 // -----------------------------------------------------------------------------
615
StartDrag(Window * pWindow,sal_Int8 nDragSourceActions,const Link & rLnk,sal_Int32 nDragPointer,sal_Int32 nDragImage)616 void TransferDataContainer::StartDrag(
617 Window* pWindow, sal_Int8 nDragSourceActions,
618 const Link& rLnk, sal_Int32 nDragPointer, sal_Int32 nDragImage )
619 {
620 pImpl->aFinshedLnk = rLnk;
621 TransferableHelper::StartDrag( pWindow, nDragSourceActions,
622 nDragPointer, nDragImage );
623 }
624
625 // -----------------------------------------------------------------------------
626
DragFinished(sal_Int8 nDropAction)627 void TransferDataContainer::DragFinished( sal_Int8 nDropAction )
628 {
629 if( pImpl->aFinshedLnk.IsSet() )
630 pImpl->aFinshedLnk.Call( &nDropAction );
631 }
632